From 85c675d0d09a45a135bddd15d7b385f8758c32fb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 19:35:05 +0200 Subject: Adding upstream version 6.7.7. Signed-off-by: Daniel Baumann --- drivers/usb/chipidea/Kconfig | 4 ++ drivers/usb/chipidea/Makefile | 1 + drivers/usb/chipidea/ci.h | 2 + drivers/usb/chipidea/ci_hdrc_npcm.c | 114 +++++++++++++++++++++++++++++++++++ drivers/usb/chipidea/ci_hdrc_tegra.c | 16 +++-- drivers/usb/chipidea/ci_hdrc_usb2.c | 13 ++-- drivers/usb/chipidea/core.c | 44 ++++++++------ drivers/usb/chipidea/otg.c | 5 +- 8 files changed, 162 insertions(+), 37 deletions(-) create mode 100644 drivers/usb/chipidea/ci_hdrc_npcm.c (limited to 'drivers/usb/chipidea') diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index c815824a0b..bab45bc623 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -43,6 +43,10 @@ config USB_CHIPIDEA_MSM tristate "Enable MSM hsusb glue driver" if EXPERT default USB_CHIPIDEA +config USB_CHIPIDEA_NPCM + tristate "Enable NPCM hsusb glue driver" if EXPERT + default USB_CHIPIDEA + config USB_CHIPIDEA_IMX tristate "Enable i.MX USB glue driver" if EXPERT depends on OF diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 71afeab97e..718cb24603 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -13,6 +13,7 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o +obj-$(CONFIG_USB_CHIPIDEA_NPCM) += ci_hdrc_npcm.o obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index d9bb3d3f02..2a38e1eb65 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -176,6 +176,7 @@ struct hw_bank { * @enabled_otg_timer_bits: bits of enabled otg timers * @next_otg_timer: next nearest enabled timer to be expired * @work: work for role changing + * @power_lost_work: work for power lost handling * @wq: workqueue thread * @qh_pool: allocation pool for queue heads * @td_pool: allocation pool for transfer descriptors @@ -226,6 +227,7 @@ struct ci_hdrc { enum otg_fsm_timer next_otg_timer; struct usb_role_switch *role_switch; struct work_struct work; + struct work_struct power_lost_work; struct workqueue_struct *wq; struct dma_pool *qh_pool; diff --git a/drivers/usb/chipidea/ci_hdrc_npcm.c b/drivers/usb/chipidea/ci_hdrc_npcm.c new file mode 100644 index 0000000000..e4a191e02c --- /dev/null +++ b/drivers/usb/chipidea/ci_hdrc_npcm.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2023 Nuvoton Technology corporation. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ci.h" + +struct npcm_udc_data { + struct platform_device *ci; + struct clk *core_clk; + struct ci_hdrc_platform_data pdata; +}; + +static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned event) +{ + struct device *dev = ci->dev->parent; + + switch (event) { + case CI_HDRC_CONTROLLER_RESET_EVENT: + /* clear all mode bits */ + hw_write(ci, OP_USBMODE, 0xffffffff, 0x0); + break; + default: + dev_dbg(dev, "unknown ci_hdrc event (%d)\n",event); + break; + } + + return 0; +} + +static int npcm_udc_probe(struct platform_device *pdev) +{ + int ret; + struct npcm_udc_data *ci; + struct platform_device *plat_ci; + struct device *dev = &pdev->dev; + + ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL); + if (!ci) + return -ENOMEM; + platform_set_drvdata(pdev, ci); + + ci->core_clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ci->core_clk)) + return PTR_ERR(ci->core_clk); + + ret = clk_prepare_enable(ci->core_clk); + if (ret) + return dev_err_probe(dev, ret, "failed to enable the clock: %d\n", ret); + + ci->pdata.name = dev_name(dev); + ci->pdata.capoffset = DEF_CAPOFFSET; + ci->pdata.flags = CI_HDRC_REQUIRES_ALIGNED_DMA | + CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS; + ci->pdata.phy_mode = USBPHY_INTERFACE_MODE_UTMI; + ci->pdata.notify_event = npcm_udc_notify_event; + + plat_ci = ci_hdrc_add_device(dev, pdev->resource, pdev->num_resources, + &ci->pdata); + if (IS_ERR(plat_ci)) { + ret = PTR_ERR(plat_ci); + dev_err(dev, "failed to register HDRC NPCM device: %d\n", ret); + goto clk_err; + } + + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + + return 0; + +clk_err: + clk_disable_unprepare(ci->core_clk); + return ret; +} + +static int npcm_udc_remove(struct platform_device *pdev) +{ + struct npcm_udc_data *ci = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + ci_hdrc_remove_device(ci->ci); + clk_disable_unprepare(ci->core_clk); + + return 0; +} + +static const struct of_device_id npcm_udc_dt_match[] = { + { .compatible = "nuvoton,npcm750-udc", }, + { .compatible = "nuvoton,npcm845-udc", }, + { } +}; +MODULE_DEVICE_TABLE(of, npcm_udc_dt_match); + +static struct platform_driver npcm_udc_driver = { + .probe = npcm_udc_probe, + .remove = npcm_udc_remove, + .driver = { + .name = "npcm_udc", + .of_match_table = npcm_udc_dt_match, + }, +}; + +module_platform_driver(npcm_udc_driver); + +MODULE_DESCRIPTION("NPCM USB device controller driver"); +MODULE_AUTHOR("Tomer Maimon "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 8e78bf643e..2cc3058032 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -293,14 +293,12 @@ static int tegra_usb_probe(struct platform_device *pdev) usb->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); if (IS_ERR(usb->phy)) return dev_err_probe(&pdev->dev, PTR_ERR(usb->phy), - "failed to get PHY\n"); + "failed to get PHY"); usb->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(usb->clk)) { - err = PTR_ERR(usb->clk); - dev_err(&pdev->dev, "failed to get clock: %d\n", err); - return err; - } + if (IS_ERR(usb->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(usb->clk), + "failed to get clock"); err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (err) @@ -316,7 +314,7 @@ static int tegra_usb_probe(struct platform_device *pdev) err = tegra_usb_reset_controller(&pdev->dev); if (err) { - dev_err(&pdev->dev, "failed to reset controller: %d\n", err); + dev_err_probe(&pdev->dev, err, "failed to reset controller"); goto fail_power_off; } @@ -347,8 +345,8 @@ static int tegra_usb_probe(struct platform_device *pdev) usb->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, pdev->num_resources, &usb->data); if (IS_ERR(usb->dev)) { - err = PTR_ERR(usb->dev); - dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); + err = dev_err_probe(&pdev->dev, PTR_ERR(usb->dev), + "failed to add HDRC device"); goto phy_shutdown; } diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 1321ee67f3..97379f653b 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -51,8 +51,8 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ci_hdrc_usb2_priv *priv; struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev); + const struct ci_hdrc_platform_data *data; int ret; - const struct of_device_id *match; if (!ci_pdata) { ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); @@ -61,11 +61,10 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev) *ci_pdata = ci_default_pdata; /* struct copy */ } - match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev); - if (match && match->data) { + data = device_get_match_data(&pdev->dev); + if (data) /* struct copy */ - *ci_pdata = *(struct ci_hdrc_platform_data *)match->data; - } + *ci_pdata = *data; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -120,7 +119,7 @@ static struct platform_driver ci_hdrc_usb2_driver = { .remove_new = ci_hdrc_usb2_remove, .driver = { .name = "chipidea-usb2", - .of_match_table = of_match_ptr(ci_hdrc_usb2_of_match), + .of_match_table = ci_hdrc_usb2_of_match, }, }; module_platform_driver(ci_hdrc_usb2_driver); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 85e9c3ab66..ca71df4f32 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -856,6 +856,27 @@ static int ci_extcon_register(struct ci_hdrc *ci) return 0; } +static void ci_power_lost_work(struct work_struct *work) +{ + struct ci_hdrc *ci = container_of(work, struct ci_hdrc, power_lost_work); + enum ci_role role; + + disable_irq_nosync(ci->irq); + pm_runtime_get_sync(ci->dev); + if (!ci_otg_is_fsm_mode(ci)) { + role = ci_get_role(ci); + + if (ci->role != role) { + ci_handle_id_switch(ci); + } else if (role == CI_ROLE_GADGET) { + if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV)) + usb_gadget_vbus_connect(&ci->gadget); + } + } + pm_runtime_put_sync(ci->dev); + enable_irq(ci->irq); +} + static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -1045,6 +1066,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) spin_lock_init(&ci->lock); mutex_init(&ci->mutex); + INIT_WORK(&ci->power_lost_work, ci_power_lost_work); + ci->dev = dev; ci->platdata = dev_get_platdata(dev); ci->imx28_write_fix = !!(ci->platdata->flags & @@ -1396,25 +1419,6 @@ static int ci_suspend(struct device *dev) return 0; } -static void ci_handle_power_lost(struct ci_hdrc *ci) -{ - enum ci_role role; - - disable_irq_nosync(ci->irq); - if (!ci_otg_is_fsm_mode(ci)) { - role = ci_get_role(ci); - - if (ci->role != role) { - ci_handle_id_switch(ci); - } else if (role == CI_ROLE_GADGET) { - if (ci->is_otg && hw_read_otgsc(ci, OTGSC_BSV)) - usb_gadget_vbus_connect(&ci->gadget); - } - } - - enable_irq(ci->irq); -} - static int ci_resume(struct device *dev) { struct ci_hdrc *ci = dev_get_drvdata(dev); @@ -1446,7 +1450,7 @@ static int ci_resume(struct device *dev) ci_role(ci)->resume(ci, power_lost); if (power_lost) - ci_handle_power_lost(ci); + queue_work(system_freezable_wq, &ci->power_lost_work); if (ci->supports_runtime_pm) { pm_runtime_disable(dev); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index f5490f2a5b..647e98f4e3 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -130,8 +130,11 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) void ci_handle_vbus_change(struct ci_hdrc *ci) { - if (!ci->is_otg) + if (!ci->is_otg) { + if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS) + usb_gadget_vbus_connect(&ci->gadget); return; + } if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active) usb_gadget_vbus_connect(&ci->gadget); -- cgit v1.2.3