Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'pwrseq-updates-for-v7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull power sequencing updates from Bartosz Golaszewski:
"For this release we have an extension of the pwrseq-pcie-m2 driver
with support for PCIe M.2 Key E connectors.

The rest of the commits fulfill a supporting role: document the
hardware in DT bindings, provide required serdev helpers (this has
been provided in an immutable branch to Rob Herring so you may see it
in his PR as well) and is followed up by some Kconfig fixes from Arnd.

Summary:

- add support for the PCIe M.2 Key E connectors in pwrseq-pcie-m2

- describe PCIe M.2 Mechanical Key E connectors in DT bindings

- add serdev helpers for looking up devices by OF nodes

- minor serdev core rework to enable support for PCIe M.2 Key E
connectors"

* tag 'pwrseq-updates-for-v7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
power: sequencing: pcie-m2: add SERIAL_DEV_BUS dependency
power: sequencing: pcie-m2: enforce PCI and OF dependencies
power: sequencing: pcie-m2: Create serdev device for WCN7850 bluetooth
power: sequencing: pcie-m2: Add support for PCIe M.2 Key E connectors
dt-bindings: connector: Add PCIe M.2 Mechanical Key E connector
dt-bindings: serial: Document the graph port
serdev: Do not return -ENODEV from of_serdev_register_devices() if external connector is used
serdev: Add an API to find the serdev controller associated with the devicetree node
serdev: Convert to_serdev_*() helpers to macros and use container_of_const()

+563 -28
+184
Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/connector/pcie-m2-e-connector.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: PCIe M.2 Mechanical Key E Connector 8 + 9 + maintainers: 10 + - Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> 11 + 12 + description: 13 + A PCIe M.2 E connector node represents a physical PCIe M.2 Mechanical Key E 14 + connector. Mechanical Key E connectors are used to connect Wireless 15 + Connectivity devices including combinations of Wi-Fi, BT, NFC to the host 16 + machine over interfaces like PCIe/SDIO, USB/UART+PCM, and I2C. 17 + 18 + properties: 19 + compatible: 20 + const: pcie-m2-e-connector 21 + 22 + vpcie3v3-supply: 23 + description: A phandle to the regulator for 3.3v supply. 24 + 25 + vpcie1v8-supply: 26 + description: A phandle to the regulator for VIO 1.8v supply. 27 + 28 + i2c-parent: 29 + $ref: /schemas/types.yaml#/definitions/phandle 30 + description: I2C interface 31 + 32 + clocks: 33 + description: 32.768 KHz Suspend Clock (SUSCLK) input from the host system to 34 + the M.2 card. Refer, PCI Express M.2 Specification r4.0, sec 3.1.12.1 for 35 + more details. 36 + maxItems: 1 37 + 38 + w-disable1-gpios: 39 + description: GPIO output to W_DISABLE1# signal. This signal is used by the 40 + host system to disable WiFi radio in the M.2 card. Refer, PCI Express M.2 41 + Specification r4.0, sec 3.1.12.3 for more details. 42 + maxItems: 1 43 + 44 + w-disable2-gpios: 45 + description: GPIO output to W_DISABLE2# signal. This signal is used by the 46 + host system to disable BT radio in the M.2 card. Refer, PCI Express M.2 47 + Specification r4.0, sec 3.1.12.3 for more details. 48 + maxItems: 1 49 + 50 + viocfg-gpios: 51 + description: GPIO input to IO voltage configuration (VIO_CFG) signal. The 52 + card drives this signal to indicate to the host system whether the card 53 + supports an independent IO voltage domain for sideband signals. Refer, 54 + PCI Express M.2 Specification r4.0, sec 3.1.15.1 for more details. 55 + maxItems: 1 56 + 57 + uart-wake-gpios: 58 + description: GPIO input to UART_WAKE# signal. The card asserts this signal 59 + to wake the host system and initiate UART interface communication. Refer, 60 + PCI Express M.2 Specification r4.0, sec 3.1.8.1 for more details. 61 + maxItems: 1 62 + 63 + sdio-wake-gpios: 64 + description: GPIO input to SDIO_WAKE# signal. The card asserts this signal 65 + to wake the host system and initiate SDIO interface communication. Refer, 66 + PCI Express M.2 Specification r4.0, sec 3.1.7 for more details. 67 + maxItems: 1 68 + 69 + sdio-reset-gpios: 70 + description: GPIO output to SDIO_RESET# signal. This signal is used by the 71 + host system to reset SDIO interface of the M.2 card. Refer, PCI Express 72 + M.2 Specification r4.0, sec 3.1.7 for more details. 73 + maxItems: 1 74 + 75 + vendor-porta-gpios: 76 + description: GPIO for the first vendor specific signal (VENDOR_PORTA). This 77 + signal's functionality is defined by the card manufacturer and may be 78 + used for proprietary features. Refer the card vendor's documentation for 79 + details. 80 + maxItems: 1 81 + 82 + vendor-portb-gpios: 83 + description: GPIO for the second vendor specific signal (VENDOR_PORTB). This 84 + signal's functionality is defined by the card manufacturer and may be 85 + used for proprietary features. Refer the card vendor's documentation for 86 + details. 87 + maxItems: 1 88 + 89 + vendor-portc-gpios: 90 + description: GPIO for the third vendor specific signal (VENDOR_PORTC). This 91 + signal's functionality is defined by the card manufacturer and may be 92 + used for proprietary features. Refer the card vendor's documentation for 93 + details. 94 + maxItems: 1 95 + 96 + ports: 97 + $ref: /schemas/graph.yaml#/properties/ports 98 + description: OF graph bindings modeling the interfaces exposed on the 99 + connector. Since a single connector can have multiple interfaces, every 100 + interface has an assigned OF graph port number as described below. 101 + 102 + properties: 103 + port@0: 104 + $ref: /schemas/graph.yaml#/properties/port 105 + description: PCIe interface for Wi-Fi 106 + 107 + port@1: 108 + $ref: /schemas/graph.yaml#/properties/port 109 + description: SDIO interface for Wi-Fi 110 + 111 + port@2: 112 + $ref: /schemas/graph.yaml#/properties/port 113 + description: USB 2.0 interface for BT 114 + 115 + port@3: 116 + $ref: /schemas/graph.yaml#/properties/port 117 + description: UART interface for BT 118 + 119 + port@4: 120 + $ref: /schemas/graph.yaml#/properties/port 121 + description: PCM/I2S interface 122 + 123 + anyOf: 124 + - anyOf: 125 + - required: 126 + - port@0 127 + - required: 128 + - port@1 129 + - anyOf: 130 + - required: 131 + - port@2 132 + - required: 133 + - port@3 134 + 135 + required: 136 + - compatible 137 + - vpcie3v3-supply 138 + 139 + additionalProperties: false 140 + 141 + examples: 142 + # PCI M.2 Key E connector for Wi-Fi/BT with PCIe/UART interfaces 143 + - | 144 + #include <dt-bindings/gpio/gpio.h> 145 + 146 + connector { 147 + compatible = "pcie-m2-e-connector"; 148 + vpcie3v3-supply = <&vreg_wcn_3p3>; 149 + vpcie1v8-supply = <&vreg_l15b_1p8>; 150 + i2c-parent = <&i2c0>; 151 + w-disable1-gpios = <&tlmm 115 GPIO_ACTIVE_LOW>; 152 + w-disable2-gpios = <&tlmm 116 GPIO_ACTIVE_LOW>; 153 + viocfg-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; 154 + uart-wake-gpios = <&tlmm 118 GPIO_ACTIVE_LOW>; 155 + sdio-wake-gpios = <&tlmm 119 GPIO_ACTIVE_LOW>; 156 + sdio-reset-gpios = <&tlmm 120 GPIO_ACTIVE_LOW>; 157 + 158 + ports { 159 + #address-cells = <1>; 160 + #size-cells = <0>; 161 + 162 + port@0 { 163 + reg = <0>; 164 + #address-cells = <1>; 165 + #size-cells = <0>; 166 + 167 + endpoint@0 { 168 + reg = <0>; 169 + remote-endpoint = <&pcie4_port0_ep>; 170 + }; 171 + }; 172 + 173 + port@3 { 174 + reg = <3>; 175 + #address-cells = <1>; 176 + #size-cells = <0>; 177 + 178 + endpoint@0 { 179 + reg = <0>; 180 + remote-endpoint = <&uart14_ep>; 181 + }; 182 + }; 183 + }; 184 + };
+3
Documentation/devicetree/bindings/serial/serial.yaml
··· 87 87 description: 88 88 TX FIFO threshold configuration (in bytes). 89 89 90 + port: 91 + $ref: /schemas/graph.yaml#/properties/port 92 + 90 93 patternProperties: 91 94 "^(bluetooth|bluetooth-gnss|embedded-controller|gnss|gps|mcu|onewire)$": 92 95 if:
+1
MAINTAINERS
··· 21064 21064 M: Manivannan Sadhasivam <mani@kernel.org> 21065 21065 L: linux-pci@vger.kernel.org 21066 21066 S: Maintained 21067 + F: Documentation/devicetree/bindings/connector/pcie-m2-e-connector.yaml 21067 21068 F: Documentation/devicetree/bindings/connector/pcie-m2-m-connector.yaml 21068 21069 F: drivers/power/sequencing/pwrseq-pcie-m2.c 21069 21070
+4 -1
drivers/power/sequencing/Kconfig
··· 37 37 38 38 config POWER_SEQUENCING_PCIE_M2 39 39 tristate "PCIe M.2 connector power sequencing driver" 40 - depends on OF || COMPILE_TEST 40 + depends on OF 41 + depends on PCI 42 + depends on SERIAL_DEV_BUS 43 + select OF_DYNAMIC 41 44 help 42 45 Say Y here to enable the power sequencing driver for PCIe M.2 43 46 connectors. This driver handles the power sequencing for the M.2
+332 -14
drivers/power/sequencing/pwrseq-pcie-m2.c
··· 5 5 */ 6 6 7 7 #include <linux/device.h> 8 + #include <linux/delay.h> 9 + #include <linux/gpio/consumer.h> 8 10 #include <linux/mod_devicetable.h> 9 11 #include <linux/module.h> 10 12 #include <linux/of.h> 11 13 #include <linux/of_graph.h> 14 + #include <linux/of_platform.h> 15 + #include <linux/pci.h> 12 16 #include <linux/platform_device.h> 13 17 #include <linux/pwrseq/provider.h> 14 18 #include <linux/regulator/consumer.h> 19 + #include <linux/serdev.h> 15 20 #include <linux/slab.h> 16 21 17 22 struct pwrseq_pcie_m2_pdata { ··· 30 25 struct regulator_bulk_data *regs; 31 26 size_t num_vregs; 32 27 struct notifier_block nb; 28 + struct gpio_desc *w_disable1_gpio; 29 + struct gpio_desc *w_disable2_gpio; 30 + struct serdev_device *serdev; 31 + struct of_changeset *ocs; 32 + struct device *dev; 33 33 }; 34 34 35 - static int pwrseq_pcie_m2_m_vregs_enable(struct pwrseq_device *pwrseq) 35 + static int pwrseq_pcie_m2_vregs_enable(struct pwrseq_device *pwrseq) 36 36 { 37 37 struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 38 38 39 39 return regulator_bulk_enable(ctx->num_vregs, ctx->regs); 40 40 } 41 41 42 - static int pwrseq_pcie_m2_m_vregs_disable(struct pwrseq_device *pwrseq) 42 + static int pwrseq_pcie_m2_vregs_disable(struct pwrseq_device *pwrseq) 43 43 { 44 44 struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 45 45 ··· 53 43 54 44 static const struct pwrseq_unit_data pwrseq_pcie_m2_vregs_unit_data = { 55 45 .name = "regulators-enable", 56 - .enable = pwrseq_pcie_m2_m_vregs_enable, 57 - .disable = pwrseq_pcie_m2_m_vregs_disable, 46 + .enable = pwrseq_pcie_m2_vregs_enable, 47 + .disable = pwrseq_pcie_m2_vregs_disable, 58 48 }; 59 49 60 - static const struct pwrseq_unit_data *pwrseq_pcie_m2_m_unit_deps[] = { 50 + static const struct pwrseq_unit_data *pwrseq_pcie_m2_unit_deps[] = { 61 51 &pwrseq_pcie_m2_vregs_unit_data, 62 52 NULL 63 53 }; 64 54 55 + static int pwrseq_pci_m2_e_uart_enable(struct pwrseq_device *pwrseq) 56 + { 57 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 58 + 59 + return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 0); 60 + } 61 + 62 + static int pwrseq_pci_m2_e_uart_disable(struct pwrseq_device *pwrseq) 63 + { 64 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 65 + 66 + return gpiod_set_value_cansleep(ctx->w_disable2_gpio, 1); 67 + } 68 + 69 + static const struct pwrseq_unit_data pwrseq_pcie_m2_e_uart_unit_data = { 70 + .name = "uart-enable", 71 + .deps = pwrseq_pcie_m2_unit_deps, 72 + .enable = pwrseq_pci_m2_e_uart_enable, 73 + .disable = pwrseq_pci_m2_e_uart_disable, 74 + }; 75 + 76 + static int pwrseq_pci_m2_e_pcie_enable(struct pwrseq_device *pwrseq) 77 + { 78 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 79 + 80 + return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 0); 81 + } 82 + 83 + static int pwrseq_pci_m2_e_pcie_disable(struct pwrseq_device *pwrseq) 84 + { 85 + struct pwrseq_pcie_m2_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); 86 + 87 + return gpiod_set_value_cansleep(ctx->w_disable1_gpio, 1); 88 + } 89 + 90 + static const struct pwrseq_unit_data pwrseq_pcie_m2_e_pcie_unit_data = { 91 + .name = "pcie-enable", 92 + .deps = pwrseq_pcie_m2_unit_deps, 93 + .enable = pwrseq_pci_m2_e_pcie_enable, 94 + .disable = pwrseq_pci_m2_e_pcie_disable, 95 + }; 96 + 65 97 static const struct pwrseq_unit_data pwrseq_pcie_m2_m_pcie_unit_data = { 66 98 .name = "pcie-enable", 67 - .deps = pwrseq_pcie_m2_m_unit_deps, 99 + .deps = pwrseq_pcie_m2_unit_deps, 100 + }; 101 + 102 + static int pwrseq_pcie_m2_e_pwup_delay(struct pwrseq_device *pwrseq) 103 + { 104 + /* 105 + * FIXME: This delay is only required for some Qcom WLAN/BT cards like 106 + * WCN7850 and not for all devices. But currently, there is no way to 107 + * identify the device model before enumeration. 108 + */ 109 + msleep(50); 110 + 111 + return 0; 112 + } 113 + 114 + static const struct pwrseq_target_data pwrseq_pcie_m2_e_uart_target_data = { 115 + .name = "uart", 116 + .unit = &pwrseq_pcie_m2_e_uart_unit_data, 117 + .post_enable = pwrseq_pcie_m2_e_pwup_delay, 118 + }; 119 + 120 + static const struct pwrseq_target_data pwrseq_pcie_m2_e_pcie_target_data = { 121 + .name = "pcie", 122 + .unit = &pwrseq_pcie_m2_e_pcie_unit_data, 123 + .post_enable = pwrseq_pcie_m2_e_pwup_delay, 68 124 }; 69 125 70 126 static const struct pwrseq_target_data pwrseq_pcie_m2_m_pcie_target_data = { ··· 138 62 .unit = &pwrseq_pcie_m2_m_pcie_unit_data, 139 63 }; 140 64 65 + static const struct pwrseq_target_data *pwrseq_pcie_m2_e_targets[] = { 66 + &pwrseq_pcie_m2_e_pcie_target_data, 67 + &pwrseq_pcie_m2_e_uart_target_data, 68 + NULL 69 + }; 70 + 141 71 static const struct pwrseq_target_data *pwrseq_pcie_m2_m_targets[] = { 142 72 &pwrseq_pcie_m2_m_pcie_target_data, 143 73 NULL 74 + }; 75 + 76 + static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_e_of_data = { 77 + .targets = pwrseq_pcie_m2_e_targets, 144 78 }; 145 79 146 80 static const struct pwrseq_pcie_m2_pdata pwrseq_pcie_m2_m_of_data = { ··· 177 91 return PWRSEQ_NO_MATCH; 178 92 } 179 93 180 - static void pwrseq_pcie_m2_free_regulators(void *data) 94 + static int pwrseq_m2_pcie_create_bt_node(struct pwrseq_pcie_m2_ctx *ctx, 95 + struct device_node *parent) 181 96 { 182 - struct pwrseq_pcie_m2_ctx *ctx = data; 97 + struct device *dev = ctx->dev; 98 + struct device_node *np; 99 + int ret; 183 100 184 - regulator_bulk_free(ctx->num_vregs, ctx->regs); 101 + ctx->ocs = kzalloc_obj(*ctx->ocs); 102 + if (!ctx->ocs) 103 + return -ENOMEM; 104 + 105 + of_changeset_init(ctx->ocs); 106 + 107 + np = of_changeset_create_node(ctx->ocs, parent, "bluetooth"); 108 + if (!np) { 109 + dev_err(dev, "Failed to create bluetooth node\n"); 110 + ret = -ENODEV; 111 + goto err_destroy_changeset; 112 + } 113 + 114 + ret = of_changeset_add_prop_string(ctx->ocs, np, "compatible", "qcom,wcn7850-bt"); 115 + if (ret) { 116 + dev_err(dev, "Failed to add bluetooth compatible: %d\n", ret); 117 + goto err_destroy_changeset; 118 + } 119 + 120 + ret = of_changeset_apply(ctx->ocs); 121 + if (ret) { 122 + dev_err(dev, "Failed to apply changeset: %d\n", ret); 123 + goto err_destroy_changeset; 124 + } 125 + 126 + ret = device_add_of_node(&ctx->serdev->dev, np); 127 + if (ret) { 128 + dev_err(dev, "Failed to add OF node: %d\n", ret); 129 + goto err_revert_changeset; 130 + } 131 + 132 + return 0; 133 + 134 + err_revert_changeset: 135 + of_changeset_revert(ctx->ocs); 136 + err_destroy_changeset: 137 + of_changeset_destroy(ctx->ocs); 138 + kfree(ctx->ocs); 139 + ctx->ocs = NULL; 140 + 141 + return ret; 142 + } 143 + 144 + static int pwrseq_pcie_m2_create_serdev(struct pwrseq_pcie_m2_ctx *ctx) 145 + { 146 + struct serdev_controller *serdev_ctrl; 147 + struct device *dev = ctx->dev; 148 + int ret; 149 + 150 + struct device_node *serdev_parent __free(device_node) = 151 + of_graph_get_remote_node(dev_of_node(ctx->dev), 3, 0); 152 + if (!serdev_parent) 153 + return 0; 154 + 155 + serdev_ctrl = of_find_serdev_controller_by_node(serdev_parent); 156 + if (!serdev_ctrl) 157 + return 0; 158 + 159 + /* Bail out if the device was already attached to this controller */ 160 + if (serdev_ctrl->serdev) { 161 + serdev_controller_put(serdev_ctrl); 162 + return 0; 163 + } 164 + 165 + ctx->serdev = serdev_device_alloc(serdev_ctrl); 166 + if (!ctx->serdev) { 167 + ret = -ENOMEM; 168 + goto err_put_ctrl; 169 + } 170 + 171 + ret = pwrseq_m2_pcie_create_bt_node(ctx, serdev_parent); 172 + if (ret) 173 + goto err_free_serdev; 174 + 175 + ret = serdev_device_add(ctx->serdev); 176 + if (ret) { 177 + dev_err(dev, "Failed to add serdev for WCN7850: %d\n", ret); 178 + goto err_free_dt_node; 179 + } 180 + 181 + serdev_controller_put(serdev_ctrl); 182 + 183 + return 0; 184 + 185 + err_free_dt_node: 186 + device_remove_of_node(&ctx->serdev->dev); 187 + of_changeset_revert(ctx->ocs); 188 + of_changeset_destroy(ctx->ocs); 189 + kfree(ctx->ocs); 190 + ctx->ocs = NULL; 191 + err_free_serdev: 192 + serdev_device_put(ctx->serdev); 193 + ctx->serdev = NULL; 194 + err_put_ctrl: 195 + serdev_controller_put(serdev_ctrl); 196 + 197 + return ret; 198 + } 199 + 200 + static void pwrseq_pcie_m2_remove_serdev(struct pwrseq_pcie_m2_ctx *ctx) 201 + { 202 + if (ctx->serdev) { 203 + device_remove_of_node(&ctx->serdev->dev); 204 + serdev_device_remove(ctx->serdev); 205 + ctx->serdev = NULL; 206 + } 207 + 208 + if (ctx->ocs) { 209 + of_changeset_revert(ctx->ocs); 210 + of_changeset_destroy(ctx->ocs); 211 + kfree(ctx->ocs); 212 + ctx->ocs = NULL; 213 + } 214 + } 215 + 216 + static int pwrseq_m2_pcie_notify(struct notifier_block *nb, unsigned long action, 217 + void *data) 218 + { 219 + struct pwrseq_pcie_m2_ctx *ctx = container_of(nb, struct pwrseq_pcie_m2_ctx, nb); 220 + struct pci_dev *pdev = to_pci_dev(data); 221 + int ret; 222 + 223 + /* 224 + * Check whether the PCI device is associated with this M.2 connector or 225 + * not, by comparing the OF node of the PCI device parent and the Port 0 226 + * (PCIe) remote node parent OF node. 227 + */ 228 + struct device_node *pci_parent __free(device_node) = 229 + of_graph_get_remote_node(dev_of_node(ctx->dev), 0, 0); 230 + if (!pci_parent || (pci_parent != pdev->dev.parent->of_node)) 231 + return NOTIFY_DONE; 232 + 233 + switch (action) { 234 + case BUS_NOTIFY_ADD_DEVICE: 235 + /* Create serdev device for WCN7850 */ 236 + if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) { 237 + ret = pwrseq_pcie_m2_create_serdev(ctx); 238 + if (ret) 239 + return notifier_from_errno(ret); 240 + } 241 + break; 242 + case BUS_NOTIFY_REMOVED_DEVICE: 243 + /* Destroy serdev device for WCN7850 */ 244 + if (pdev->vendor == PCI_VENDOR_ID_QCOM && pdev->device == 0x1107) 245 + pwrseq_pcie_m2_remove_serdev(ctx); 246 + 247 + break; 248 + } 249 + 250 + return NOTIFY_OK; 251 + } 252 + 253 + static bool pwrseq_pcie_m2_check_remote_node(struct device *dev, u8 port, u8 endpoint, 254 + const char *node) 255 + { 256 + struct device_node *remote __free(device_node) = 257 + of_graph_get_remote_node(dev_of_node(dev), port, endpoint); 258 + 259 + if (remote && of_node_name_eq(remote, node)) 260 + return true; 261 + 262 + return false; 263 + } 264 + 265 + /* 266 + * If the connector exposes a non-discoverable bus like UART, the respective 267 + * protocol device needs to be created manually with the help of the notifier 268 + * of the discoverable bus like PCIe. 269 + */ 270 + static int pwrseq_pcie_m2_register_notifier(struct pwrseq_pcie_m2_ctx *ctx, struct device *dev) 271 + { 272 + int ret; 273 + 274 + /* 275 + * Register a PCI notifier for Key E connector that has PCIe as Port 276 + * 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface. 277 + */ 278 + if (pwrseq_pcie_m2_check_remote_node(dev, 3, 0, "serial")) { 279 + if (pwrseq_pcie_m2_check_remote_node(dev, 0, 0, "pcie")) { 280 + ctx->dev = dev; 281 + ctx->nb.notifier_call = pwrseq_m2_pcie_notify; 282 + ret = bus_register_notifier(&pci_bus_type, &ctx->nb); 283 + if (ret) 284 + return dev_err_probe(dev, ret, 285 + "Failed to register notifier for serdev\n"); 286 + } 287 + } 288 + 289 + return 0; 185 290 } 186 291 187 292 static int pwrseq_pcie_m2_probe(struct platform_device *pdev) ··· 386 109 if (!ctx) 387 110 return -ENOMEM; 388 111 112 + platform_set_drvdata(pdev, ctx); 389 113 ctx->of_node = dev_of_node(dev); 390 114 ctx->pdata = device_get_match_data(dev); 391 115 if (!ctx->pdata) ··· 405 127 406 128 ctx->num_vregs = ret; 407 129 408 - ret = devm_add_action_or_reset(dev, pwrseq_pcie_m2_free_regulators, ctx); 409 - if (ret) 410 - return ret; 130 + ctx->w_disable1_gpio = devm_gpiod_get_optional(dev, "w-disable1", GPIOD_OUT_HIGH); 131 + if (IS_ERR(ctx->w_disable1_gpio)) { 132 + ret = dev_err_probe(dev, PTR_ERR(ctx->w_disable1_gpio), 133 + "Failed to get the W_DISABLE_1# GPIO\n"); 134 + goto err_free_regulators; 135 + } 136 + 137 + ctx->w_disable2_gpio = devm_gpiod_get_optional(dev, "w-disable2", GPIOD_OUT_HIGH); 138 + if (IS_ERR(ctx->w_disable2_gpio)) { 139 + ret = dev_err_probe(dev, PTR_ERR(ctx->w_disable2_gpio), 140 + "Failed to get the W_DISABLE_2# GPIO\n"); 141 + goto err_free_regulators; 142 + } 411 143 412 144 config.parent = dev; 413 145 config.owner = THIS_MODULE; ··· 426 138 config.targets = ctx->pdata->targets; 427 139 428 140 ctx->pwrseq = devm_pwrseq_device_register(dev, &config); 429 - if (IS_ERR(ctx->pwrseq)) 430 - return dev_err_probe(dev, PTR_ERR(ctx->pwrseq), 141 + if (IS_ERR(ctx->pwrseq)) { 142 + ret = dev_err_probe(dev, PTR_ERR(ctx->pwrseq), 431 143 "Failed to register the power sequencer\n"); 144 + goto err_free_regulators; 145 + } 146 + 147 + /* 148 + * Register a notifier for creating protocol devices for 149 + * non-discoverable busses like UART. 150 + */ 151 + ret = pwrseq_pcie_m2_register_notifier(ctx, dev); 152 + if (ret) 153 + goto err_free_regulators; 432 154 433 155 return 0; 156 + 157 + err_free_regulators: 158 + regulator_bulk_free(ctx->num_vregs, ctx->regs); 159 + 160 + return ret; 161 + } 162 + 163 + static void pwrseq_pcie_m2_remove(struct platform_device *pdev) 164 + { 165 + struct pwrseq_pcie_m2_ctx *ctx = platform_get_drvdata(pdev); 166 + 167 + bus_unregister_notifier(&pci_bus_type, &ctx->nb); 168 + pwrseq_pcie_m2_remove_serdev(ctx); 169 + 170 + regulator_bulk_free(ctx->num_vregs, ctx->regs); 434 171 } 435 172 436 173 static const struct of_device_id pwrseq_pcie_m2_of_match[] = { 437 174 { 438 175 .compatible = "pcie-m2-m-connector", 439 176 .data = &pwrseq_pcie_m2_m_of_data, 177 + }, 178 + { 179 + .compatible = "pcie-m2-e-connector", 180 + .data = &pwrseq_pcie_m2_e_of_data, 440 181 }, 441 182 { } 442 183 }; ··· 477 160 .of_match_table = pwrseq_pcie_m2_of_match, 478 161 }, 479 162 .probe = pwrseq_pcie_m2_probe, 163 + .remove = pwrseq_pcie_m2_remove, 480 164 }; 481 165 module_platform_driver(pwrseq_pcie_m2_driver); 482 166
+27 -1
drivers/tty/serdev/core.c
··· 12 12 #include <linux/kernel.h> 13 13 #include <linux/module.h> 14 14 #include <linux/of.h> 15 + #include <linux/of_graph.h> 15 16 #include <linux/of_device.h> 16 17 #include <linux/pm_domain.h> 17 18 #include <linux/pm_runtime.h> ··· 515 514 } 516 515 EXPORT_SYMBOL_GPL(serdev_controller_alloc); 517 516 517 + #ifdef CONFIG_OF 518 + /** 519 + * of_find_serdev_controller_by_node() - Find the serdev controller associated 520 + * with the devicetree node 521 + * @node: Devicetree node 522 + * 523 + * Return: Pointer to the serdev controller associated with the node. NULL if 524 + * the controller is not found. Caller is responsible for calling 525 + * serdev_controller_put() to drop the reference. 526 + */ 527 + struct serdev_controller *of_find_serdev_controller_by_node(struct device_node *node) 528 + { 529 + struct device *dev = bus_find_device_by_of_node(&serdev_bus_type, node); 530 + 531 + return (dev && dev->type == &serdev_ctrl_type) ? to_serdev_controller(dev) : NULL; 532 + } 533 + EXPORT_SYMBOL_GPL(of_find_serdev_controller_by_node); 534 + #endif 535 + 518 536 static int of_serdev_register_devices(struct serdev_controller *ctrl) 519 537 { 520 538 struct device_node *node; ··· 562 542 } else 563 543 found = true; 564 544 } 565 - if (!found) 545 + 546 + /* 547 + * When the serdev controller is connected to an external connector like 548 + * M.2 in DT, then the serdev devices may be created dynamically by the 549 + * connector driver. 550 + */ 551 + if (!found && !of_graph_is_present(dev_of_node(&ctrl->dev))) 566 552 return -ENODEV; 567 553 568 554 return 0;
+12 -12
include/linux/serdev.h
··· 49 49 struct mutex write_lock; 50 50 }; 51 51 52 - static inline struct serdev_device *to_serdev_device(struct device *d) 53 - { 54 - return container_of(d, struct serdev_device, dev); 55 - } 52 + #define to_serdev_device(d) container_of_const(d, struct serdev_device, dev) 56 53 57 54 /** 58 55 * struct serdev_device_driver - serdev slave device driver ··· 65 68 void (*shutdown)(struct serdev_device *); 66 69 }; 67 70 68 - static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d) 69 - { 70 - return container_of(d, struct serdev_device_driver, driver); 71 - } 71 + #define to_serdev_device_driver(d) container_of_const(d, struct serdev_device_driver, driver) 72 72 73 73 enum serdev_parity { 74 74 SERDEV_PARITY_NONE, ··· 106 112 const struct serdev_controller_ops *ops; 107 113 }; 108 114 109 - static inline struct serdev_controller *to_serdev_controller(struct device *d) 110 - { 111 - return container_of(d, struct serdev_controller, dev); 112 - } 115 + #define to_serdev_controller(d) container_of_const(d, struct serdev_controller, dev) 113 116 114 117 static inline void *serdev_device_get_drvdata(const struct serdev_device *serdev) 115 118 { ··· 333 342 return false; 334 343 } 335 344 #endif /* CONFIG_ACPI */ 345 + 346 + #ifdef CONFIG_OF 347 + struct serdev_controller *of_find_serdev_controller_by_node(struct device_node *node); 348 + #else 349 + static inline struct serdev_controller *of_find_serdev_controller_by_node(struct device_node *node) 350 + { 351 + return NULL; 352 + } 353 + #endif /* CONFIG_OF */ 336 354 337 355 #endif /*_LINUX_SERDEV_H */