mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-15 16:26:45 +07:00
9f57ed095f
Detailed description for this pull request: 1. Add new 'extcon-usbc-cros-ec.c' driver - ChromeOS Embedded Controller extcon driver supports the detection of the Display Port (EXTCON_DISP_DP) through USB C-type and contol it. 2. Update extcon core - Modify the description for both functions and structures in order to improve the readability and give the more correct guide about the role of functions because there are different explanation even if the same arguments. - Keep the indentation with tab instead of space - Remove the following deprecated extcon API. The deprecated API are exchanged on all of linux tree. : extcon_get_cable_state_() -> extcon_get_state() : extcon_set_cable_state_() -> extcon_set_state_sync() 3. Include the two immutable branch as following: - ib-extcon-mfd-4.14 for the 'extcon-ubsc-cros-ec.c' driver because the patches of 'extcon-ubsc-cros-ec.c' touch the MFD directory. - ib-extcon-usb-phy-4.14 for removing the deprecated extcon API because the usb/phy driver usese the deprecated extcon API. So, this immutable branch alters the extcon API and then remove them from extcon. 4. Fix minor issue of extcon driver - Fix the MHL detection on extcon-max77693.c - Convert to using %pOF instead of full_name on extcon.c - Add 'const' kerywod for acpi_device_id on extcon-intel-int3496.c -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJZn3XJAAoJEJzN3yze689Tat0P/jnTEqEleNCDBYx4SW/c7ilO KCNXEEfgtD0sIon3KPt6Zbc0Na+QmD7DSrdlPsc0864k7Vrb/M+bshETtrxC/fQi WW8SaRHNLePCH0UnayUoukYtlui1zWbfdJ8HLQqfQILQy2LVIaA7famL8wuHHXJR 4zl69EQPTODBKt9akHjQ2pLuucN/6KAl4QcBje4eY/c+mMpyjo6Ivi6vRCFpL66T J+rBobTvRoMUwTaIlmquwoVgdMpk2DA9NXOypGT3slIeIqfyUf+7TUtBGbVrCmvj o+zVap5pcZhf6KXfi4OZUbDdgXpIn2V1p5ztAq0JlW2LcyguZ1bZs3EJAsyRS0aS 3ykru6e5KqH4vcMwcxkgatPKhSSPyC93ETdvx55IF7uP6qH8ym1hgtDKr7FrPW0+ Md/gO8YPgFMZRUG2rAbCJO/zFbS4aNh0X6eOOCmsraxy0IQBE/p41zw8Tp7Jgupv oxV1beXyB2DLBCGkj12baGUzePZent/vse3dPbl8YHiubQCgAa4u4NO70EU/T9W+ 3PeJEK4o3vw9aDBGTMINRUSMKQGCAkf4VL+wyBn8k/LTYWPP1YsA1+beX1E184vB vS0nnjhJP8VphfAAx5+eYnep6HPTUPwlyi9CR/vbSG8HmPkfIDslQ8700VsmsEkn 6mMDK+pd9FGjs6nwwO5d =oQMu -----END PGP SIGNATURE----- Merge tag 'extcon-next-for-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next Chanwoo writes: Update extcon for 4.14 Detailed description for this pull request: 1. Add new 'extcon-usbc-cros-ec.c' driver - ChromeOS Embedded Controller extcon driver supports the detection of the Display Port (EXTCON_DISP_DP) through USB C-type and contol it. 2. Update extcon core - Modify the description for both functions and structures in order to improve the readability and give the more correct guide about the role of functions because there are different explanation even if the same arguments. - Keep the indentation with tab instead of space - Remove the following deprecated extcon API. The deprecated API are exchanged on all of linux tree. : extcon_get_cable_state_() -> extcon_get_state() : extcon_set_cable_state_() -> extcon_set_state_sync() 3. Include the two immutable branch as following: - ib-extcon-mfd-4.14 for the 'extcon-ubsc-cros-ec.c' driver because the patches of 'extcon-ubsc-cros-ec.c' touch the MFD directory. - ib-extcon-usb-phy-4.14 for removing the deprecated extcon API because the usb/phy driver usese the deprecated extcon API. So, this immutable branch alters the extcon API and then remove them from extcon. 4. Fix minor issue of extcon driver - Fix the MHL detection on extcon-max77693.c - Convert to using %pOF instead of full_name on extcon.c - Add 'const' kerywod for acpi_device_id on extcon-intel-int3496.c
345 lines
7.5 KiB
C
345 lines
7.5 KiB
C
/*
|
|
* snps_udc_plat.c - Synopsys UDC Platform Driver
|
|
*
|
|
* Copyright (C) 2016 Broadcom
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation version 2.
|
|
*
|
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
* kind, whether express or implied; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/extcon.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/phy/phy.h>
|
|
#include <linux/module.h>
|
|
#include <linux/dmapool.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/moduleparam.h>
|
|
#include "amd5536udc.h"
|
|
|
|
/* description */
|
|
#define UDC_MOD_DESCRIPTION "Synopsys UDC platform driver"
|
|
|
|
static void start_udc(struct udc *udc)
|
|
{
|
|
if (udc->driver) {
|
|
dev_info(udc->dev, "Connecting...\n");
|
|
udc_enable_dev_setup_interrupts(udc);
|
|
udc_basic_init(udc);
|
|
udc->connected = 1;
|
|
}
|
|
}
|
|
|
|
static void stop_udc(struct udc *udc)
|
|
{
|
|
int tmp;
|
|
u32 reg;
|
|
|
|
spin_lock(&udc->lock);
|
|
|
|
/* Flush the receieve fifo */
|
|
reg = readl(&udc->regs->ctl);
|
|
reg |= AMD_BIT(UDC_DEVCTL_SRX_FLUSH);
|
|
writel(reg, &udc->regs->ctl);
|
|
|
|
reg = readl(&udc->regs->ctl);
|
|
reg &= ~(AMD_BIT(UDC_DEVCTL_SRX_FLUSH));
|
|
writel(reg, &udc->regs->ctl);
|
|
dev_dbg(udc->dev, "ep rx queue flushed\n");
|
|
|
|
/* Mask interrupts. Required more so when the
|
|
* UDC is connected to a DRD phy.
|
|
*/
|
|
udc_mask_unused_interrupts(udc);
|
|
|
|
/* Disconnect gadget driver */
|
|
if (udc->driver) {
|
|
spin_unlock(&udc->lock);
|
|
udc->driver->disconnect(&udc->gadget);
|
|
spin_lock(&udc->lock);
|
|
|
|
/* empty queues */
|
|
for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
|
|
empty_req_queue(&udc->ep[tmp]);
|
|
}
|
|
udc->connected = 0;
|
|
|
|
spin_unlock(&udc->lock);
|
|
dev_info(udc->dev, "Device disconnected\n");
|
|
}
|
|
|
|
static void udc_drd_work(struct work_struct *work)
|
|
{
|
|
struct udc *udc;
|
|
|
|
udc = container_of(to_delayed_work(work),
|
|
struct udc, drd_work);
|
|
|
|
if (udc->conn_type) {
|
|
dev_dbg(udc->dev, "idle -> device\n");
|
|
start_udc(udc);
|
|
} else {
|
|
dev_dbg(udc->dev, "device -> idle\n");
|
|
stop_udc(udc);
|
|
}
|
|
}
|
|
|
|
static int usbd_connect_notify(struct notifier_block *self,
|
|
unsigned long event, void *ptr)
|
|
{
|
|
struct udc *udc = container_of(self, struct udc, nb);
|
|
|
|
dev_dbg(udc->dev, "%s: event: %lu\n", __func__, event);
|
|
|
|
udc->conn_type = event;
|
|
|
|
schedule_delayed_work(&udc->drd_work, 0);
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static int udc_plat_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct resource *res;
|
|
struct udc *udc;
|
|
int ret;
|
|
|
|
udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
|
|
if (!udc)
|
|
return -ENOMEM;
|
|
|
|
spin_lock_init(&udc->lock);
|
|
udc->dev = dev;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
udc->virt_addr = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(udc->regs))
|
|
return PTR_ERR(udc->regs);
|
|
|
|
/* udc csr registers base */
|
|
udc->csr = udc->virt_addr + UDC_CSR_ADDR;
|
|
|
|
/* dev registers base */
|
|
udc->regs = udc->virt_addr + UDC_DEVCFG_ADDR;
|
|
|
|
/* ep registers base */
|
|
udc->ep_regs = udc->virt_addr + UDC_EPREGS_ADDR;
|
|
|
|
/* fifo's base */
|
|
udc->rxfifo = (u32 __iomem *)(udc->virt_addr + UDC_RXFIFO_ADDR);
|
|
udc->txfifo = (u32 __iomem *)(udc->virt_addr + UDC_TXFIFO_ADDR);
|
|
|
|
udc->phys_addr = (unsigned long)res->start;
|
|
|
|
udc->irq = irq_of_parse_and_map(dev->of_node, 0);
|
|
if (udc->irq <= 0) {
|
|
dev_err(dev, "Can't parse and map interrupt\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
udc->udc_phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
|
|
if (IS_ERR(udc->udc_phy)) {
|
|
dev_err(dev, "Failed to obtain phy from device tree\n");
|
|
return PTR_ERR(udc->udc_phy);
|
|
}
|
|
|
|
ret = phy_init(udc->udc_phy);
|
|
if (ret) {
|
|
dev_err(dev, "UDC phy init failed");
|
|
return ret;
|
|
}
|
|
|
|
ret = phy_power_on(udc->udc_phy);
|
|
if (ret) {
|
|
dev_err(dev, "UDC phy power on failed");
|
|
phy_exit(udc->udc_phy);
|
|
return ret;
|
|
}
|
|
|
|
/* Register for extcon if supported */
|
|
if (of_get_property(dev->of_node, "extcon", NULL)) {
|
|
udc->edev = extcon_get_edev_by_phandle(dev, 0);
|
|
if (IS_ERR(udc->edev)) {
|
|
if (PTR_ERR(udc->edev) == -EPROBE_DEFER)
|
|
return -EPROBE_DEFER;
|
|
dev_err(dev, "Invalid or missing extcon\n");
|
|
ret = PTR_ERR(udc->edev);
|
|
goto exit_phy;
|
|
}
|
|
|
|
udc->nb.notifier_call = usbd_connect_notify;
|
|
ret = extcon_register_notifier(udc->edev, EXTCON_USB,
|
|
&udc->nb);
|
|
if (ret < 0) {
|
|
dev_err(dev, "Can't register extcon device\n");
|
|
goto exit_phy;
|
|
}
|
|
|
|
ret = extcon_get_state(udc->edev, EXTCON_USB);
|
|
if (ret < 0) {
|
|
dev_err(dev, "Can't get cable state\n");
|
|
goto exit_extcon;
|
|
} else if (ret) {
|
|
udc->conn_type = ret;
|
|
}
|
|
INIT_DELAYED_WORK(&udc->drd_work, udc_drd_work);
|
|
}
|
|
|
|
/* init dma pools */
|
|
if (use_dma) {
|
|
ret = init_dma_pools(udc);
|
|
if (ret != 0)
|
|
goto exit_extcon;
|
|
}
|
|
|
|
ret = devm_request_irq(dev, udc->irq, udc_irq, IRQF_SHARED,
|
|
"snps-udc", udc);
|
|
if (ret < 0) {
|
|
dev_err(dev, "Request irq %d failed for UDC\n", udc->irq);
|
|
goto exit_dma;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, udc);
|
|
udc->chiprev = UDC_BCM_REV;
|
|
|
|
if (udc_probe(udc)) {
|
|
ret = -ENODEV;
|
|
goto exit_dma;
|
|
}
|
|
dev_info(dev, "Synopsys UDC platform driver probe successful\n");
|
|
|
|
return 0;
|
|
|
|
exit_dma:
|
|
if (use_dma)
|
|
free_dma_pools(udc);
|
|
exit_extcon:
|
|
if (udc->edev)
|
|
extcon_unregister_notifier(udc->edev, EXTCON_USB, &udc->nb);
|
|
exit_phy:
|
|
if (udc->udc_phy) {
|
|
phy_power_off(udc->udc_phy);
|
|
phy_exit(udc->udc_phy);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int udc_plat_remove(struct platform_device *pdev)
|
|
{
|
|
struct udc *dev;
|
|
|
|
dev = platform_get_drvdata(pdev);
|
|
|
|
usb_del_gadget_udc(&dev->gadget);
|
|
/* gadget driver must not be registered */
|
|
if (WARN_ON(dev->driver))
|
|
return 0;
|
|
|
|
/* dma pool cleanup */
|
|
free_dma_pools(dev);
|
|
|
|
udc_remove(dev);
|
|
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
|
if (dev->drd_wq) {
|
|
flush_workqueue(dev->drd_wq);
|
|
destroy_workqueue(dev->drd_wq);
|
|
}
|
|
|
|
phy_power_off(dev->udc_phy);
|
|
phy_exit(dev->udc_phy);
|
|
extcon_unregister_notifier(dev->edev, EXTCON_USB, &dev->nb);
|
|
|
|
dev_info(&pdev->dev, "Synopsys UDC platform driver removed\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static int udc_plat_suspend(struct device *dev)
|
|
{
|
|
struct udc *udc;
|
|
|
|
udc = dev_get_drvdata(dev);
|
|
stop_udc(udc);
|
|
|
|
if (extcon_get_state(udc->edev, EXTCON_USB) > 0) {
|
|
dev_dbg(udc->dev, "device -> idle\n");
|
|
stop_udc(udc);
|
|
}
|
|
phy_power_off(udc->udc_phy);
|
|
phy_exit(udc->udc_phy);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int udc_plat_resume(struct device *dev)
|
|
{
|
|
struct udc *udc;
|
|
int ret;
|
|
|
|
udc = dev_get_drvdata(dev);
|
|
|
|
ret = phy_init(udc->udc_phy);
|
|
if (ret) {
|
|
dev_err(udc->dev, "UDC phy init failure");
|
|
return ret;
|
|
}
|
|
|
|
ret = phy_power_on(udc->udc_phy);
|
|
if (ret) {
|
|
dev_err(udc->dev, "UDC phy power on failure");
|
|
phy_exit(udc->udc_phy);
|
|
return ret;
|
|
}
|
|
|
|
if (extcon_get_state(udc->edev, EXTCON_USB) > 0) {
|
|
dev_dbg(udc->dev, "idle -> device\n");
|
|
start_udc(udc);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static const struct dev_pm_ops udc_plat_pm_ops = {
|
|
.suspend = udc_plat_suspend,
|
|
.resume = udc_plat_resume,
|
|
};
|
|
#endif
|
|
|
|
#if defined(CONFIG_OF)
|
|
static const struct of_device_id of_udc_match[] = {
|
|
{ .compatible = "brcm,ns2-udc", },
|
|
{ .compatible = "brcm,cygnus-udc", },
|
|
{ .compatible = "brcm,iproc-udc", },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, of_udc_match);
|
|
#endif
|
|
|
|
static struct platform_driver udc_plat_driver = {
|
|
.probe = udc_plat_probe,
|
|
.remove = udc_plat_remove,
|
|
.driver = {
|
|
.name = "snps-udc-plat",
|
|
.of_match_table = of_match_ptr(of_udc_match),
|
|
#ifdef CONFIG_PM_SLEEP
|
|
.pm = &udc_plat_pm_ops,
|
|
#endif
|
|
},
|
|
};
|
|
module_platform_driver(udc_plat_driver);
|
|
|
|
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
|
|
MODULE_AUTHOR("Broadcom");
|
|
MODULE_LICENSE("GPL v2");
|