| .. | .. |
|---|
| 2 | 2 | /* |
|---|
| 3 | 3 | * xhci-plat.c - xHCI host controller driver platform Bus Glue. |
|---|
| 4 | 4 | * |
|---|
| 5 | | - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com |
|---|
| 5 | + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com |
|---|
| 6 | 6 | * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
|---|
| 7 | 7 | * |
|---|
| 8 | 8 | * A lot of code borrowed from the Linux xHCI driver. |
|---|
| .. | .. |
|---|
| 18 | 18 | #include <linux/usb/phy.h> |
|---|
| 19 | 19 | #include <linux/slab.h> |
|---|
| 20 | 20 | #include <linux/acpi.h> |
|---|
| 21 | +#include <linux/usb/of.h> |
|---|
| 21 | 22 | |
|---|
| 22 | 23 | #include "xhci.h" |
|---|
| 23 | 24 | #include "xhci-plat.h" |
|---|
| .. | .. |
|---|
| 43 | 44 | priv->plat_start(hcd); |
|---|
| 44 | 45 | } |
|---|
| 45 | 46 | |
|---|
| 47 | +static int xhci_priv_plat_setup(struct usb_hcd *hcd) |
|---|
| 48 | +{ |
|---|
| 49 | + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
|---|
| 50 | + |
|---|
| 51 | + if (!priv->plat_setup) |
|---|
| 52 | + return 0; |
|---|
| 53 | + |
|---|
| 54 | + return priv->plat_setup(hcd); |
|---|
| 55 | +} |
|---|
| 56 | + |
|---|
| 46 | 57 | static int xhci_priv_init_quirk(struct usb_hcd *hcd) |
|---|
| 47 | 58 | { |
|---|
| 48 | 59 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
|---|
| .. | .. |
|---|
| 51 | 62 | return 0; |
|---|
| 52 | 63 | |
|---|
| 53 | 64 | return priv->init_quirk(hcd); |
|---|
| 65 | +} |
|---|
| 66 | + |
|---|
| 67 | +static int xhci_priv_suspend_quirk(struct usb_hcd *hcd) |
|---|
| 68 | +{ |
|---|
| 69 | + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
|---|
| 70 | + |
|---|
| 71 | + if (!priv->suspend_quirk) |
|---|
| 72 | + return 0; |
|---|
| 73 | + |
|---|
| 74 | + return priv->suspend_quirk(hcd); |
|---|
| 54 | 75 | } |
|---|
| 55 | 76 | |
|---|
| 56 | 77 | static int xhci_priv_resume_quirk(struct usb_hcd *hcd) |
|---|
| .. | .. |
|---|
| 65 | 86 | |
|---|
| 66 | 87 | static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) |
|---|
| 67 | 88 | { |
|---|
| 89 | + struct xhci_plat_priv *priv = xhci_to_priv(xhci); |
|---|
| 90 | + |
|---|
| 68 | 91 | /* |
|---|
| 69 | 92 | * As of now platform drivers don't provide MSI support so we ensure |
|---|
| 70 | 93 | * here that the generic code does not try to make a pci_dev from our |
|---|
| 71 | 94 | * dev struct in order to setup MSI |
|---|
| 72 | 95 | */ |
|---|
| 73 | | - xhci->quirks |= XHCI_PLAT; |
|---|
| 96 | + xhci->quirks |= XHCI_PLAT | priv->quirks; |
|---|
| 74 | 97 | } |
|---|
| 75 | 98 | |
|---|
| 76 | 99 | /* called during probe() after chip reset completes */ |
|---|
| .. | .. |
|---|
| 97 | 120 | .init_quirk = xhci_mvebu_mbus_init_quirk, |
|---|
| 98 | 121 | }; |
|---|
| 99 | 122 | |
|---|
| 123 | +static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { |
|---|
| 124 | + .plat_setup = xhci_mvebu_a3700_plat_setup, |
|---|
| 125 | + .init_quirk = xhci_mvebu_a3700_init_quirk, |
|---|
| 126 | +}; |
|---|
| 127 | + |
|---|
| 100 | 128 | static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { |
|---|
| 101 | | - .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, |
|---|
| 102 | | - .init_quirk = xhci_rcar_init_quirk, |
|---|
| 103 | | - .plat_start = xhci_rcar_start, |
|---|
| 104 | | - .resume_quirk = xhci_rcar_resume_quirk, |
|---|
| 129 | + SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V1) |
|---|
| 105 | 130 | }; |
|---|
| 106 | 131 | |
|---|
| 107 | 132 | static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { |
|---|
| 108 | | - .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3, |
|---|
| 109 | | - .init_quirk = xhci_rcar_init_quirk, |
|---|
| 110 | | - .plat_start = xhci_rcar_start, |
|---|
| 111 | | - .resume_quirk = xhci_rcar_resume_quirk, |
|---|
| 133 | + SET_XHCI_PLAT_PRIV_FOR_RCAR(XHCI_RCAR_FIRMWARE_NAME_V3) |
|---|
| 134 | +}; |
|---|
| 135 | + |
|---|
| 136 | +static const struct xhci_plat_priv xhci_plat_brcm = { |
|---|
| 137 | + .quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS, |
|---|
| 112 | 138 | }; |
|---|
| 113 | 139 | |
|---|
| 114 | 140 | static const struct of_device_id usb_xhci_of_match[] = { |
|---|
| .. | .. |
|---|
| 116 | 142 | .compatible = "generic-xhci", |
|---|
| 117 | 143 | }, { |
|---|
| 118 | 144 | .compatible = "xhci-platform", |
|---|
| 145 | +#ifndef CONFIG_ARCH_ROCKCHIP |
|---|
| 119 | 146 | }, { |
|---|
| 120 | 147 | .compatible = "marvell,armada-375-xhci", |
|---|
| 121 | 148 | .data = &xhci_plat_marvell_armada, |
|---|
| 122 | 149 | }, { |
|---|
| 123 | 150 | .compatible = "marvell,armada-380-xhci", |
|---|
| 124 | 151 | .data = &xhci_plat_marvell_armada, |
|---|
| 152 | + }, { |
|---|
| 153 | + .compatible = "marvell,armada3700-xhci", |
|---|
| 154 | + .data = &xhci_plat_marvell_armada3700, |
|---|
| 125 | 155 | }, { |
|---|
| 126 | 156 | .compatible = "renesas,xhci-r8a7790", |
|---|
| 127 | 157 | .data = &xhci_plat_renesas_rcar_gen2, |
|---|
| .. | .. |
|---|
| 143 | 173 | }, { |
|---|
| 144 | 174 | .compatible = "renesas,rcar-gen3-xhci", |
|---|
| 145 | 175 | .data = &xhci_plat_renesas_rcar_gen3, |
|---|
| 176 | + }, { |
|---|
| 177 | + .compatible = "brcm,xhci-brcm-v2", |
|---|
| 178 | + .data = &xhci_plat_brcm, |
|---|
| 179 | + }, { |
|---|
| 180 | + .compatible = "brcm,bcm7445-xhci", |
|---|
| 181 | + .data = &xhci_plat_brcm, |
|---|
| 182 | +#endif |
|---|
| 146 | 183 | }, |
|---|
| 147 | 184 | {}, |
|---|
| 148 | 185 | }; |
|---|
| 149 | 186 | MODULE_DEVICE_TABLE(of, usb_xhci_of_match); |
|---|
| 150 | 187 | #endif |
|---|
| 188 | + |
|---|
| 189 | +static struct xhci_plat_priv_overwrite xhci_plat_vendor_overwrite; |
|---|
| 190 | + |
|---|
| 191 | +int xhci_plat_register_vendor_ops(struct xhci_vendor_ops *vendor_ops) |
|---|
| 192 | +{ |
|---|
| 193 | + if (vendor_ops == NULL) |
|---|
| 194 | + return -EINVAL; |
|---|
| 195 | + |
|---|
| 196 | + xhci_plat_vendor_overwrite.vendor_ops = vendor_ops; |
|---|
| 197 | + |
|---|
| 198 | + return 0; |
|---|
| 199 | +} |
|---|
| 200 | +EXPORT_SYMBOL_GPL(xhci_plat_register_vendor_ops); |
|---|
| 201 | + |
|---|
| 202 | +static int xhci_vendor_init(struct xhci_hcd *xhci) |
|---|
| 203 | +{ |
|---|
| 204 | + struct xhci_vendor_ops *ops = NULL; |
|---|
| 205 | + |
|---|
| 206 | + if (xhci_plat_vendor_overwrite.vendor_ops) |
|---|
| 207 | + ops = xhci->vendor_ops = xhci_plat_vendor_overwrite.vendor_ops; |
|---|
| 208 | + |
|---|
| 209 | + if (ops && ops->vendor_init) |
|---|
| 210 | + return ops->vendor_init(xhci); |
|---|
| 211 | + return 0; |
|---|
| 212 | +} |
|---|
| 213 | + |
|---|
| 214 | +static void xhci_vendor_cleanup(struct xhci_hcd *xhci) |
|---|
| 215 | +{ |
|---|
| 216 | + struct xhci_vendor_ops *ops = xhci_vendor_get_ops(xhci); |
|---|
| 217 | + |
|---|
| 218 | + if (ops && ops->vendor_cleanup) |
|---|
| 219 | + ops->vendor_cleanup(xhci); |
|---|
| 220 | + |
|---|
| 221 | + xhci->vendor_ops = NULL; |
|---|
| 222 | +} |
|---|
| 151 | 223 | |
|---|
| 152 | 224 | static int xhci_plat_probe(struct platform_device *pdev) |
|---|
| 153 | 225 | { |
|---|
| .. | .. |
|---|
| 157 | 229 | struct xhci_hcd *xhci; |
|---|
| 158 | 230 | struct resource *res; |
|---|
| 159 | 231 | struct usb_hcd *hcd; |
|---|
| 160 | | - struct clk *clk; |
|---|
| 161 | | - struct clk *reg_clk; |
|---|
| 162 | 232 | int ret; |
|---|
| 163 | 233 | int irq; |
|---|
| 234 | + struct xhci_plat_priv *priv = NULL; |
|---|
| 235 | + |
|---|
| 164 | 236 | |
|---|
| 165 | 237 | if (usb_disabled()) |
|---|
| 166 | 238 | return -ENODEV; |
|---|
| .. | .. |
|---|
| 217 | 289 | goto disable_runtime; |
|---|
| 218 | 290 | } |
|---|
| 219 | 291 | |
|---|
| 220 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 221 | | - hcd->regs = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 292 | + hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
|---|
| 222 | 293 | if (IS_ERR(hcd->regs)) { |
|---|
| 223 | 294 | ret = PTR_ERR(hcd->regs); |
|---|
| 224 | 295 | goto put_hcd; |
|---|
| .. | .. |
|---|
| 227 | 298 | hcd->rsrc_start = res->start; |
|---|
| 228 | 299 | hcd->rsrc_len = resource_size(res); |
|---|
| 229 | 300 | |
|---|
| 301 | + xhci = hcd_to_xhci(hcd); |
|---|
| 302 | + |
|---|
| 230 | 303 | /* |
|---|
| 231 | 304 | * Not all platforms have clks so it is not an error if the |
|---|
| 232 | 305 | * clock do not exist. |
|---|
| 233 | 306 | */ |
|---|
| 234 | | - reg_clk = devm_clk_get(&pdev->dev, "reg"); |
|---|
| 235 | | - if (!IS_ERR(reg_clk)) { |
|---|
| 236 | | - ret = clk_prepare_enable(reg_clk); |
|---|
| 237 | | - if (ret) |
|---|
| 238 | | - goto put_hcd; |
|---|
| 239 | | - } else if (PTR_ERR(reg_clk) == -EPROBE_DEFER) { |
|---|
| 240 | | - ret = -EPROBE_DEFER; |
|---|
| 307 | + xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg"); |
|---|
| 308 | + if (IS_ERR(xhci->reg_clk)) { |
|---|
| 309 | + ret = PTR_ERR(xhci->reg_clk); |
|---|
| 241 | 310 | goto put_hcd; |
|---|
| 242 | 311 | } |
|---|
| 243 | 312 | |
|---|
| 244 | | - clk = devm_clk_get(&pdev->dev, NULL); |
|---|
| 245 | | - if (!IS_ERR(clk)) { |
|---|
| 246 | | - ret = clk_prepare_enable(clk); |
|---|
| 247 | | - if (ret) |
|---|
| 248 | | - goto disable_reg_clk; |
|---|
| 249 | | - } else if (PTR_ERR(clk) == -EPROBE_DEFER) { |
|---|
| 250 | | - ret = -EPROBE_DEFER; |
|---|
| 313 | + ret = clk_prepare_enable(xhci->reg_clk); |
|---|
| 314 | + if (ret) |
|---|
| 315 | + goto put_hcd; |
|---|
| 316 | + |
|---|
| 317 | + xhci->clk = devm_clk_get_optional(&pdev->dev, NULL); |
|---|
| 318 | + if (IS_ERR(xhci->clk)) { |
|---|
| 319 | + ret = PTR_ERR(xhci->clk); |
|---|
| 251 | 320 | goto disable_reg_clk; |
|---|
| 252 | 321 | } |
|---|
| 253 | 322 | |
|---|
| 254 | | - xhci = hcd_to_xhci(hcd); |
|---|
| 255 | | - priv_match = of_device_get_match_data(&pdev->dev); |
|---|
| 256 | | - if (priv_match) { |
|---|
| 257 | | - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
|---|
| 323 | + ret = clk_prepare_enable(xhci->clk); |
|---|
| 324 | + if (ret) |
|---|
| 325 | + goto disable_reg_clk; |
|---|
| 258 | 326 | |
|---|
| 327 | + if (pdev->dev.of_node) |
|---|
| 328 | + priv_match = of_device_get_match_data(&pdev->dev); |
|---|
| 329 | + else |
|---|
| 330 | + priv_match = dev_get_platdata(&pdev->dev); |
|---|
| 331 | + |
|---|
| 332 | + if (priv_match) { |
|---|
| 333 | + priv = hcd_to_xhci_priv(hcd); |
|---|
| 259 | 334 | /* Just copy data for now */ |
|---|
| 260 | | - if (priv_match) |
|---|
| 261 | | - *priv = *priv_match; |
|---|
| 335 | + *priv = *priv_match; |
|---|
| 262 | 336 | } |
|---|
| 263 | 337 | |
|---|
| 264 | | - device_wakeup_enable(hcd->self.controller); |
|---|
| 338 | + device_set_wakeup_capable(&pdev->dev, true); |
|---|
| 265 | 339 | |
|---|
| 266 | | - xhci->clk = clk; |
|---|
| 267 | | - xhci->reg_clk = reg_clk; |
|---|
| 268 | 340 | xhci->main_hcd = hcd; |
|---|
| 269 | 341 | xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, |
|---|
| 270 | 342 | dev_name(&pdev->dev), hcd); |
|---|
| .. | .. |
|---|
| 288 | 360 | if (device_property_read_bool(tmpdev, "quirk-broken-port-ped")) |
|---|
| 289 | 361 | xhci->quirks |= XHCI_BROKEN_PORT_PED; |
|---|
| 290 | 362 | |
|---|
| 291 | | - if (device_property_read_bool(tmpdev, "xhci-slow-suspend")) |
|---|
| 292 | | - xhci->quirks |= XHCI_SLOW_SUSPEND; |
|---|
| 293 | | - |
|---|
| 294 | | - if (device_property_read_bool(tmpdev, "xhci-trb-ent-quirk")) |
|---|
| 295 | | - xhci->quirks |= XHCI_TRB_ENT_QUIRK; |
|---|
| 296 | | - |
|---|
| 297 | | - if (device_property_read_bool(tmpdev, "usb3-dis-autosuspend")) |
|---|
| 298 | | - xhci->quirks |= XHCI_DIS_AUTOSUSPEND; |
|---|
| 299 | | - |
|---|
| 300 | | - if (device_property_read_bool(tmpdev, |
|---|
| 301 | | - "xhci-warm-reset-on-suspend")) |
|---|
| 302 | | - xhci->quirks |= XHCI_WARM_RESET_ON_SUSPEND; |
|---|
| 363 | + if (device_property_read_bool(tmpdev, "quirk-skip-phy-init")) |
|---|
| 364 | + xhci->quirks |= XHCI_SKIP_PHY_INIT; |
|---|
| 303 | 365 | |
|---|
| 304 | 366 | if (device_property_read_bool(tmpdev, |
|---|
| 305 | 367 | "xhci-u2-broken-suspend")) |
|---|
| 306 | 368 | xhci->quirks |= XHCI_U2_BROKEN_SUSPEND; |
|---|
| 307 | | - |
|---|
| 308 | | - if (device_property_read_bool(tmpdev, "quirk-skip-phy-init")) |
|---|
| 309 | | - xhci->quirks |= XHCI_SKIP_PHY_INIT; |
|---|
| 310 | 369 | |
|---|
| 311 | 370 | device_property_read_u32(tmpdev, "imod-interval-ns", |
|---|
| 312 | 371 | &xhci->imod_interval); |
|---|
| .. | .. |
|---|
| 324 | 383 | goto put_usb3_hcd; |
|---|
| 325 | 384 | } |
|---|
| 326 | 385 | |
|---|
| 327 | | - xhci->shared_hcd->usb_phy = devm_usb_get_phy(sysdev, |
|---|
| 328 | | - USB_PHY_TYPE_USB3); |
|---|
| 329 | | - if (IS_ERR(xhci->shared_hcd->usb_phy)) { |
|---|
| 330 | | - ret = PTR_ERR(xhci->shared_hcd->usb_phy); |
|---|
| 331 | | - if (ret == -EPROBE_DEFER) |
|---|
| 332 | | - goto put_usb3_hcd; |
|---|
| 333 | | - xhci->shared_hcd->usb_phy = NULL; |
|---|
| 386 | + ret = xhci_vendor_init(xhci); |
|---|
| 387 | + if (ret) |
|---|
| 388 | + goto disable_usb_phy; |
|---|
| 389 | + |
|---|
| 390 | + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); |
|---|
| 391 | + xhci->shared_hcd->tpl_support = hcd->tpl_support; |
|---|
| 392 | + |
|---|
| 393 | + if (priv) { |
|---|
| 394 | + ret = xhci_priv_plat_setup(hcd); |
|---|
| 395 | + if (ret) |
|---|
| 396 | + goto disable_usb_phy; |
|---|
| 334 | 397 | } |
|---|
| 335 | 398 | |
|---|
| 336 | | - if (xhci->quirks & XHCI_SKIP_PHY_INIT) |
|---|
| 399 | + if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))) |
|---|
| 337 | 400 | hcd->skip_phy_initialization = 1; |
|---|
| 401 | + |
|---|
| 402 | + if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK)) |
|---|
| 403 | + xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK; |
|---|
| 338 | 404 | |
|---|
| 339 | 405 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); |
|---|
| 340 | 406 | if (ret) |
|---|
| .. | .. |
|---|
| 369 | 435 | usb_put_hcd(xhci->shared_hcd); |
|---|
| 370 | 436 | |
|---|
| 371 | 437 | disable_clk: |
|---|
| 372 | | - clk_disable_unprepare(clk); |
|---|
| 438 | + clk_disable_unprepare(xhci->clk); |
|---|
| 373 | 439 | |
|---|
| 374 | 440 | disable_reg_clk: |
|---|
| 375 | | - clk_disable_unprepare(reg_clk); |
|---|
| 441 | + clk_disable_unprepare(xhci->reg_clk); |
|---|
| 376 | 442 | |
|---|
| 377 | 443 | put_hcd: |
|---|
| 378 | 444 | usb_put_hcd(hcd); |
|---|
| .. | .. |
|---|
| 400 | 466 | usb_phy_shutdown(hcd->usb_phy); |
|---|
| 401 | 467 | |
|---|
| 402 | 468 | usb_remove_hcd(hcd); |
|---|
| 403 | | - usb_put_hcd(shared_hcd); |
|---|
| 404 | 469 | |
|---|
| 470 | + xhci_vendor_cleanup(xhci); |
|---|
| 471 | + |
|---|
| 472 | + usb_put_hcd(shared_hcd); |
|---|
| 405 | 473 | clk_disable_unprepare(clk); |
|---|
| 406 | 474 | clk_disable_unprepare(reg_clk); |
|---|
| 407 | 475 | usb_put_hcd(hcd); |
|---|
| .. | .. |
|---|
| 417 | 485 | { |
|---|
| 418 | 486 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
|---|
| 419 | 487 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
|---|
| 488 | + int ret; |
|---|
| 420 | 489 | |
|---|
| 490 | + if (pm_runtime_suspended(dev)) |
|---|
| 491 | + pm_runtime_resume(dev); |
|---|
| 492 | + |
|---|
| 493 | + ret = xhci_priv_suspend_quirk(hcd); |
|---|
| 494 | + if (ret) |
|---|
| 495 | + return ret; |
|---|
| 421 | 496 | /* |
|---|
| 422 | 497 | * xhci_suspend() needs `do_wakeup` to know whether host is allowed |
|---|
| 423 | | - * to do wakeup during suspend. Since xhci_plat_suspend is currently |
|---|
| 424 | | - * only designed for system suspend, device_may_wakeup() is enough |
|---|
| 425 | | - * to dertermine whether host is allowed to do wakeup. Need to |
|---|
| 426 | | - * reconsider this when xhci_plat_suspend enlarges its scope, e.g., |
|---|
| 427 | | - * also applies to runtime suspend. |
|---|
| 498 | + * to do wakeup during suspend. |
|---|
| 428 | 499 | */ |
|---|
| 429 | | - return xhci_suspend(xhci, device_may_wakeup(dev)); |
|---|
| 500 | + ret = xhci_suspend(xhci, device_may_wakeup(dev)); |
|---|
| 501 | + if (ret) |
|---|
| 502 | + return ret; |
|---|
| 503 | + |
|---|
| 504 | + if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { |
|---|
| 505 | + clk_disable_unprepare(xhci->clk); |
|---|
| 506 | + clk_disable_unprepare(xhci->reg_clk); |
|---|
| 507 | + } |
|---|
| 508 | + |
|---|
| 509 | + return 0; |
|---|
| 430 | 510 | } |
|---|
| 431 | 511 | |
|---|
| 432 | 512 | static int __maybe_unused xhci_plat_resume(struct device *dev) |
|---|
| .. | .. |
|---|
| 435 | 515 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
|---|
| 436 | 516 | int ret; |
|---|
| 437 | 517 | |
|---|
| 518 | + if (!device_may_wakeup(dev) && (xhci->quirks & XHCI_SUSPEND_RESUME_CLKS)) { |
|---|
| 519 | + clk_prepare_enable(xhci->clk); |
|---|
| 520 | + clk_prepare_enable(xhci->reg_clk); |
|---|
| 521 | + } |
|---|
| 522 | + |
|---|
| 438 | 523 | ret = xhci_priv_resume_quirk(hcd); |
|---|
| 439 | 524 | if (ret) |
|---|
| 440 | 525 | return ret; |
|---|
| 441 | 526 | |
|---|
| 442 | | - return xhci_resume(xhci, 0); |
|---|
| 527 | + ret = xhci_resume(xhci, 0); |
|---|
| 528 | + if (ret) |
|---|
| 529 | + return ret; |
|---|
| 530 | + |
|---|
| 531 | + pm_runtime_disable(dev); |
|---|
| 532 | + pm_runtime_set_active(dev); |
|---|
| 533 | + pm_runtime_enable(dev); |
|---|
| 534 | + |
|---|
| 535 | + return 0; |
|---|
| 443 | 536 | } |
|---|
| 444 | 537 | |
|---|
| 445 | 538 | static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev) |
|---|
| 446 | 539 | { |
|---|
| 447 | 540 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
|---|
| 448 | 541 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
|---|
| 542 | + int ret; |
|---|
| 543 | + |
|---|
| 544 | + ret = xhci_priv_suspend_quirk(hcd); |
|---|
| 545 | + if (ret) |
|---|
| 546 | + return ret; |
|---|
| 449 | 547 | |
|---|
| 450 | 548 | return xhci_suspend(xhci, true); |
|---|
| 451 | 549 | } |
|---|
| .. | .. |
|---|
| 466 | 564 | NULL) |
|---|
| 467 | 565 | }; |
|---|
| 468 | 566 | |
|---|
| 567 | +#ifdef CONFIG_ACPI |
|---|
| 469 | 568 | static const struct acpi_device_id usb_xhci_acpi_match[] = { |
|---|
| 470 | 569 | /* XHCI-compliant USB Controller */ |
|---|
| 471 | 570 | { "PNP0D10", }, |
|---|
| 472 | 571 | { } |
|---|
| 473 | 572 | }; |
|---|
| 474 | 573 | MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); |
|---|
| 574 | +#endif |
|---|
| 475 | 575 | |
|---|
| 476 | 576 | static struct platform_driver usb_xhci_driver = { |
|---|
| 477 | 577 | .probe = xhci_plat_probe, |
|---|