From mboxrd@z Thu Jan 1 00:00:00 1970 From: Min Guo Subject: Re: [PATCH v5 6/6] usb: musb: Add support for MediaTek musb controller Date: Mon, 1 Apr 2019 13:35:24 +0800 Message-ID: <1554096924.19123.3.camel@mhfsdcap03> References: <1550561795-31132-1-git-send-email-min.guo@mediatek.com> <1550561795-31132-7-git-send-email-min.guo@mediatek.com> Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: Sender: linux-kernel-owner@vger.kernel.org To: Fabien Parent Cc: Bin Liu , Rob Herring , Mark Rutland , devicetree@vger.kernel.org, Yonglong Wu , hdegoede@redhat.com, tony@atomide.com, Greg Kroah-Hartman , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Matthias Brugger , Alan Stern , chunfeng.yun@mediatek.com, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org List-Id: linux-mediatek@lists.infradead.org Hi Fabien Parent, On Sat, 2019-03-30 at 09:52 +0100, Fabien Parent wrote: > Hi Min Guo, > > On Tue, Feb 19, 2019 at 8:39 AM wrote: > > > > From: Min Guo > > > > This adds support for MediaTek musb controller in > > host, peripheral and otg mode. > > There are some quirk of MediaTek musb controller, such as: > > -W1C interrupt status registers > > -Private data toggle registers > > -No dedicated DMA interrupt line > > > > Signed-off-by: Min Guo > > Signed-off-by: Yonglong Wu > > --- > > changes in v5: > > 1. Replace musb_readb() with musb_clearb() to clear common/tx/rx pending interrupts > > 2. Make musb_clearb/w() return the value of musb_readb/w() > > 3. Add driver to get child nodes of usb connector and extcon device > > > > changes in v4: > > 1. no changes > > > > changes in v3: > > suggested by Bin: > > 1. Remove 'u8/u16 data' parameter in clearb/w() hooks > > 2. Replace musb_readb/w() with musb_clearb/w() to clear interrupts status > > > > changes in v2: > > suggested by Bin: > > 1. Add summarize of MediaTek musb controller differences in the commit log > > 2. Add "|| COMPILE_TEST" in Kconfig > > 3. Move MediaTek's private toggle registers from musb_regs.h to mediatek.c > > 4. Replace musb_readl() with musb_readw() to read 16bit toggle register > > --- > > drivers/usb/musb/Kconfig | 8 +- > > drivers/usb/musb/Makefile | 1 + > > drivers/usb/musb/mediatek.c | 629 ++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 637 insertions(+), 1 deletion(-) > > create mode 100644 drivers/usb/musb/mediatek.c > > > > diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig > > index ad08895..b72b7c1 100644 > > --- a/drivers/usb/musb/Kconfig > > +++ b/drivers/usb/musb/Kconfig > > @@ -115,6 +115,12 @@ config USB_MUSB_JZ4740 > > depends on USB_MUSB_GADGET > > depends on USB_OTG_BLACKLIST_HUB > > > > +config USB_MUSB_MEDIATEK > > + tristate "MediaTek platforms" > > + depends on ARCH_MEDIATEK || COMPILE_TEST > > + depends on NOP_USB_XCEIV > > + depends on GENERIC_PHY > > + > > config USB_MUSB_AM335X_CHILD > > tristate > > > > @@ -141,7 +147,7 @@ config USB_UX500_DMA > > > > config USB_INVENTRA_DMA > > bool 'Inventra' > > - depends on USB_MUSB_OMAP2PLUS > > + depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK > > help > > Enable DMA transfers using Mentor's engine. > > > > diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile > > index 3a88c79..63d82d0 100644 > > --- a/drivers/usb/musb/Makefile > > +++ b/drivers/usb/musb/Makefile > > @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o > > obj-$(CONFIG_USB_MUSB_UX500) += ux500.o > > obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o > > obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o > > +obj-$(CONFIG_USB_MUSB_MEDIATEK) += mediatek.o > > > > > > obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o > > diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c > > new file mode 100644 > > index 0000000..946b453 > > --- /dev/null > > +++ b/drivers/usb/musb/mediatek.c > > @@ -0,0 +1,629 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2018 MediaTek Inc. > > + * > > + * Author: > > + * Min Guo > > + * Yonglong Wu > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include "musb_core.h" > > +#include "musb_dma.h" > > + > > +#define USB_L1INTS 0x00a0 > > +#define USB_L1INTM 0x00a4 > > +#define MTK_MUSB_TXFUNCADDR 0x0480 > > + > > +/* MediaTek controller toggle enable and status reg */ > > +#define MUSB_RXTOG 0x80 > > +#define MUSB_RXTOGEN 0x82 > > +#define MUSB_TXTOG 0x84 > > +#define MUSB_TXTOGEN 0x86 > > + > > +#define TX_INT_STATUS BIT(0) > > +#define RX_INT_STATUS BIT(1) > > +#define USBCOM_INT_STATUS BIT(2) > > +#define DMA_INT_STATUS BIT(3) > > + > > +#define DMA_INTR_STATUS_MSK GENMASK(7, 0) > > +#define DMA_INTR_UNMASK_SET_MSK GENMASK(31, 24) > > + > > +enum mtk_vbus_id_state { > > + MTK_ID_FLOAT = 1, > > + MTK_ID_GROUND, > > + MTK_VBUS_OFF, > > + MTK_VBUS_VALID, > > +}; > > + > > +struct mtk_glue { > > + struct device *dev; > > + struct musb *musb; > > + struct platform_device *musb_pdev; > > + struct platform_device *usb_phy; > > + struct phy *phy; > > + struct usb_phy *xceiv; > > + enum phy_mode phy_mode; > > + struct clk *main; > > + struct clk *mcu; > > + struct clk *univpll; > > + struct regulator *vbus; > > + struct extcon_dev *edev; > > + struct notifier_block vbus_nb; > > + struct notifier_block id_nb; > > +}; > > + > > +static int mtk_musb_clks_get(struct mtk_glue *glue) > > +{ > > + struct device *dev = glue->dev; > > + > > + glue->main = devm_clk_get(dev, "main"); > > + if (IS_ERR(glue->main)) { > > + dev_err(dev, "fail to get main clock\n"); > > + return PTR_ERR(glue->main); > > + } > > + > > + glue->mcu = devm_clk_get(dev, "mcu"); > > + if (IS_ERR(glue->mcu)) { > > + dev_err(dev, "fail to get mcu clock\n"); > > + return PTR_ERR(glue->mcu); > > + } > > + > > + glue->univpll = devm_clk_get(dev, "univpll"); > > + if (IS_ERR(glue->univpll)) { > > + dev_err(dev, "fail to get univpll clock\n"); > > + return PTR_ERR(glue->univpll); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_clks_enable(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + ret = clk_prepare_enable(glue->main); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable main clock\n"); > > + goto err_main_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->mcu); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable mcu clock\n"); > > + goto err_mcu_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->univpll); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable univpll clock\n"); > > + goto err_univpll_clk; > > + } > > + > > + return 0; > > + > > +err_univpll_clk: > > + clk_disable_unprepare(glue->mcu); > > +err_mcu_clk: > > + clk_disable_unprepare(glue->main); > > +err_main_clk: > > + return ret; > > +} > > + > > +static void mtk_musb_clks_disable(struct mtk_glue *glue) > > +{ > > + clk_disable_unprepare(glue->univpll); > > + clk_disable_unprepare(glue->mcu); > > + clk_disable_unprepare(glue->main); > > +} > > + > > +static void mtk_musb_set_vbus(struct musb *musb, int is_on) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + /* vbus is optional */ > > + if (!glue->vbus) > > + return; > > + > > + dev_dbg(musb->controller, "%s, is_on=%d\r\n", __func__, is_on); > > + if (is_on) { > > + ret = regulator_enable(glue->vbus); > > + if (ret) { > > + dev_err(glue->dev, "fail to enable vbus regulator\n"); > > + return; > > + } > > + } else { > > + regulator_disable(glue->vbus); > > + } > > +} > > + > > +/* > > + * switch to host: -> MTK_VBUS_OFF --> MTK_ID_GROUND > > + * switch to device: -> MTK_ID_FLOAT --> MTK_VBUS_VALID > > + */ > > +static void mtk_musb_set_mailbox(struct mtk_glue *glue, > > + enum mtk_vbus_id_state status) > > +{ > > + struct musb *musb = glue->musb; > > + u8 devctl = 0; > > + > > + dev_dbg(glue->dev, "mailbox state(%d)\n", status); > > + switch (status) { > > + case MTK_ID_GROUND: > > + phy_power_on(glue->phy); > > + devctl = readb(musb->mregs + MUSB_DEVCTL); > > + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; > > + mtk_musb_set_vbus(musb, 1); > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + devctl |= MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + MUSB_HST_MODE(musb); > > + break; > > + /* > > + * MTK_ID_FLOAT process is the same as MTK_VBUS_VALID > > + * except that turn off VBUS > > + */ > > + case MTK_ID_FLOAT: > > + mtk_musb_set_vbus(musb, 0); > > + /* fall through */ > > + case MTK_VBUS_OFF: > > + musb->xceiv->otg->state = OTG_STATE_B_IDLE; > > + devctl &= ~MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + phy_power_off(glue->phy); > > + break; > > + case MTK_VBUS_VALID: > > + phy_power_on(glue->phy); > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + MUSB_DEV_MODE(musb); > > + break; > > + default: > > + dev_err(glue->dev, "invalid state\n"); > > + } > > +} > > + > > +static int mtk_musb_id_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, id_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + else > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static int mtk_musb_vbus_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, vbus_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > + else > > + mtk_musb_set_mailbox(glue, MTK_VBUS_OFF); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static void mtk_otg_switch_init(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + /* extcon is optional */ > > + if (!glue->edev) > > + return; > > + > > + glue->vbus_nb.notifier_call = mtk_musb_vbus_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, EXTCON_USB, > > + &glue->vbus_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB\n"); > > + > > + glue->id_nb.notifier_call = mtk_musb_id_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, > > + EXTCON_USB_HOST, &glue->id_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB-HOST\n"); > > + > > + dev_dbg(glue->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", > > + extcon_get_state(glue->edev, EXTCON_USB), > > + extcon_get_state(glue->edev, EXTCON_USB_HOST)); > > + > > + /* default as host, switch to device mode if needed */ > > + if (extcon_get_state(glue->edev, EXTCON_USB_HOST) == false) > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + if (extcon_get_state(glue->edev, EXTCON_USB) == true) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > +} > > + > > +static irqreturn_t generic_interrupt(int irq, void *__hci) > > +{ > > + unsigned long flags; > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = __hci; > > + > > + spin_lock_irqsave(&musb->lock, flags); > > + musb->int_usb = musb_clearb(musb->mregs, MUSB_INTRUSB); > > + musb->int_rx = musb_clearw(musb->mregs, MUSB_INTRRX); > > + musb->int_tx = musb_clearw(musb->mregs, MUSB_INTRTX); > > + > > + if (musb->int_usb || musb->int_tx || musb->int_rx) > > + retval = musb_interrupt(musb); > > + > > + spin_unlock_irqrestore(&musb->lock, flags); > > + > > + return retval; > > +} > > + > > +static irqreturn_t mtk_musb_interrupt(int irq, void *dev_id) > > +{ > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = (struct musb *)dev_id; > > + u32 l1_ints; > > + > > + l1_ints = musb_readl(musb->mregs, USB_L1INTS) & > > + musb_readl(musb->mregs, USB_L1INTM); > > + > > + if (l1_ints & (TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS)) > > + retval = generic_interrupt(irq, musb); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + if (l1_ints & DMA_INT_STATUS) > > + retval = dma_controller_irq(irq, musb->dma_controller); > > +#endif > > + return retval; > > +} > > + > > +static u32 mtk_musb_busctl_offset(u8 epnum, u16 offset) > > +{ > > + return MTK_MUSB_TXFUNCADDR + offset + 8 * epnum; > > +} > > + > > +static u8 mtk_musb_clearb(void __iomem *addr, unsigned int offset) > > +{ > > + u8 data; > > + > > + /* W1C */ > > + data = musb_readb(addr, offset); > > + musb_writeb(addr, offset, data); > > + return data; > > +} > > + > > +static u16 mtk_musb_clearw(void __iomem *addr, unsigned int offset) > > +{ > > + u16 data; > > + > > + /* W1C */ > > + data = musb_readw(addr, offset); > > + musb_writew(addr, offset, data); > > + return data; > > +} > > + > > +static int mtk_musb_init(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + glue->musb = musb; > > + musb->phy = glue->phy; > > + musb->xceiv = glue->xceiv; > > + musb->is_host = false; > > + musb->isr = mtk_musb_interrupt; > > + ret = phy_init(glue->phy); > > + if (ret) > > + return ret; > > + > > + ret = phy_power_on(glue->phy); > > + if (ret) { > > + phy_exit(glue->phy); > > + return ret; > > + } > > + > > + phy_set_mode(glue->phy, glue->phy_mode); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + musb_writel(musb->mregs, MUSB_HSDMA_INTR, > > + DMA_INTR_STATUS_MSK | DMA_INTR_UNMASK_SET_MSK); > > +#endif > > + musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | > > + USBCOM_INT_STATUS | DMA_INT_STATUS); > > + return 0; > > +} > > + > > +static u16 mtk_musb_get_toggle(struct musb_qh *qh, int is_out) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + if (is_out) > > + toggle = musb_readw(musb->mregs, MUSB_TXTOG); > > + else > > + toggle = musb_readw(musb->mregs, MUSB_RXTOG); > > + > > + return toggle & (1 << epnum); > > +} > > + > > +static u16 mtk_musb_set_toggle(struct musb_qh *qh, int is_out, struct urb *urb) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + toggle = usb_gettoggle(urb->dev, qh->epnum, is_out); > > + > > + if (is_out) { > > + musb_writew(musb->mregs, MUSB_TXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_TXTOG, (toggle << epnum)); > > + } else { > > + musb_writew(musb->mregs, MUSB_RXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_RXTOG, (toggle << epnum)); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_set_mode(struct musb *musb, u8 mode) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + enum phy_mode new_mode; > > + > > + switch (mode) { > > + case MUSB_HOST: > > + new_mode = PHY_MODE_USB_HOST; > > + mtk_musb_set_vbus(musb, 1); > > + break; > > + case MUSB_PERIPHERAL: > > + new_mode = PHY_MODE_USB_DEVICE; > > + break; > > + case MUSB_OTG: > > + new_mode = PHY_MODE_USB_HOST; > > + break; > > + default: > > + dev_err(musb->controller->parent, > > + "Error requested mode not supported by this kernel\n"); > > + return -EINVAL; > > + } > > + if (glue->phy_mode == new_mode) > > + return 0; > > + > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + return 0; > > +} > > + > > +static int mtk_musb_exit(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + > > + phy_power_off(glue->phy); > > + phy_exit(glue->phy); > > + mtk_musb_clks_disable(glue); > > + > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > + return 0; > > +} > > + > > +static const struct musb_platform_ops mtk_musb_ops = { > > + .quirks = MUSB_DMA_INVENTRA, > > + .init = mtk_musb_init, > > + .get_toggle = mtk_musb_get_toggle, > > + .set_toggle = mtk_musb_set_toggle, > > + .exit = mtk_musb_exit, > > +#ifdef CONFIG_USB_INVENTRA_DMA > > + .dma_init = musbhs_dma_controller_create_noirq, > > + .dma_exit = musbhs_dma_controller_destroy, > > +#endif > > + .clearb = mtk_musb_clearb, > > + .clearw = mtk_musb_clearw, > > + .busctl_offset = mtk_musb_busctl_offset, > > + .set_mode = mtk_musb_set_mode, > > + .set_vbus = mtk_musb_set_vbus, > > +}; > > + > > +#define MTK_MUSB_MAX_EP_NUM 8 > > +#define MTK_MUSB_RAM_BITS 11 > > + > > +static struct musb_fifo_cfg mtk_musb_mode_cfg[] = { > > + { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 1024, }, > > + { .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 1024, }, > > + { .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 64, }, > > +}; > > + > > +static const struct musb_hdrc_config mtk_musb_hdrc_config = { > > + .fifo_cfg = mtk_musb_mode_cfg, > > + .fifo_cfg_size = ARRAY_SIZE(mtk_musb_mode_cfg), > > + .multipoint = true, > > + .dyn_fifo = true, > > + .num_eps = MTK_MUSB_MAX_EP_NUM, > > + .ram_bits = MTK_MUSB_RAM_BITS, > > +}; > > + > > +static const struct platform_device_info mtk_dev_info = { > > + .name = "musb-hdrc", > > + .id = PLATFORM_DEVID_AUTO, > > + .dma_mask = DMA_BIT_MASK(32), > > +}; > > + > > +static int mtk_musb_probe(struct platform_device *pdev) > > +{ > > + struct musb_hdrc_platform_data *pdata; > > + struct mtk_glue *glue; > > + struct platform_device_info pinfo; > > + struct device *dev = &pdev->dev; > > + struct device_node *np = dev->of_node; > > + struct device_node *child, *extcon_node; > > + int ret = -ENOMEM; > > + > > + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); > > + if (!glue) > > + return -ENOMEM; > > + > > + glue->dev = dev; > > + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); > > + if (!pdata) > > + return -ENOMEM; > > + > > + ret = mtk_musb_clks_get(glue); > > + if (ret) > > + return ret; > > + > > + pdata->config = &mtk_musb_hdrc_config; > > + pdata->platform_ops = &mtk_musb_ops; > > + > > + glue->vbus = devm_regulator_get(dev, "vbus"); > > + if (IS_ERR(glue->vbus)) { > > + dev_err(dev, "fail to get vbus\n"); > > + return PTR_ERR(glue->vbus); > > + } > > + > > + child = of_get_child_by_name(np, "connector"); > > + if (!child) { > > + dev_err(dev, "failed to find usb connector node\n"); > > + return ERR_PTR(-ENODEV); > > The 'probe' function is returning an 'int' and not a pointer. This > line should trigger a warning. OK, thanks. > > + } > > + > > + extcon_node = of_parse_phandle(child, "extcon", 0); > > + if (!extcon_node) { > > + dev_err(dev, "failed to get extcon phandle"); > > + return ERR_PTR(-ENODEV); > > Same here OK, thanks. > > + } > > + > > + glue->edev = extcon_find_edev_by_node(extcon_node); > > + if (IS_ERR(glue->edev)) { > > + dev_err(dev, "fail to get extcon\n"); > > + return PTR_ERR(glue->edev); > > + } > > + > > + pdata->mode = usb_get_dr_mode(dev); > > + switch (pdata->mode) { > > + case USB_DR_MODE_HOST: > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + break; > > + case USB_DR_MODE_PERIPHERAL: > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + break; > > + default: > > + pdata->mode = USB_DR_MODE_OTG; > > + /* FALL THROUGH */ > > + case USB_DR_MODE_OTG: > > + glue->phy_mode = PHY_MODE_USB_OTG; > > + break; > > + } > > + > > + glue->phy = devm_of_phy_get_by_index(dev, np, 0); > > + if (IS_ERR(glue->phy)) { > > + dev_err(dev, "fail to getting phy %ld\n", > > + PTR_ERR(glue->phy)); > > + return PTR_ERR(glue->phy); > > + } > > + > > + glue->usb_phy = usb_phy_generic_register(); > > + if (IS_ERR(glue->usb_phy)) { > > + dev_err(dev, "fail to registering usb-phy %ld\n", > > + PTR_ERR(glue->usb_phy)); > > + return PTR_ERR(glue->usb_phy); > > + } > > + > > + glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); > > + if (IS_ERR(glue->xceiv)) { > > + dev_err(dev, "fail to getting usb-phy %d\n", ret); > > + ret = PTR_ERR(glue->xceiv); > > + goto err_unregister_usb_phy; > > + } > > + > > + platform_set_drvdata(pdev, glue); > > + pm_runtime_enable(dev); > > + pm_runtime_get_sync(dev); > > + > > + ret = mtk_musb_clks_enable(glue); > > + if (ret) > > + goto err_enable_clk; > > + > > + pinfo = mtk_dev_info; > > + pinfo.parent = dev; > > + pinfo.res = pdev->resource; > > + pinfo.num_res = pdev->num_resources; > > + pinfo.data = pdata; > > + pinfo.size_data = sizeof(*pdata); > > + > > + glue->musb_pdev = platform_device_register_full(&pinfo); > > + if (IS_ERR(glue->musb_pdev)) { > > + ret = PTR_ERR(glue->musb_pdev); > > + dev_err(dev, "failed to register musb device: %d\n", ret); > > + goto err_device_register; > > + } > > + > > + if (pdata->mode == USB_DR_MODE_OTG) > > + mtk_otg_switch_init(glue); > > + > > + return 0; > > + > > +err_device_register: > > + mtk_musb_clks_disable(glue); > > +err_enable_clk: > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > +err_unregister_usb_phy: > > + usb_phy_generic_unregister(glue->usb_phy); > > + return ret; > > +} > > + > > +static int mtk_musb_remove(struct platform_device *pdev) > > +{ > > + struct mtk_glue *glue = platform_get_drvdata(pdev); > > + struct platform_device *usb_phy = glue->usb_phy; > > + > > + platform_device_unregister(glue->musb_pdev); > > + usb_phy_generic_unregister(usb_phy); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_OF > > +static const struct of_device_id mtk_musb_match[] = { > > + {.compatible = "mediatek,mtk-musb",}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, mtk_musb_match); > > +#endif > > + > > +static struct platform_driver mtk_musb_driver = { > > + .probe = mtk_musb_probe, > > + .remove = mtk_musb_remove, > > + .driver = { > > + .name = "musb-mtk", > > + .of_match_table = of_match_ptr(mtk_musb_match), > > + }, > > +}; > > + > > +module_platform_driver(mtk_musb_driver); > > + > > +MODULE_DESCRIPTION("MediaTek MUSB Glue Layer"); > > +MODULE_AUTHOR("Min Guo "); > > +MODULE_LICENSE("GPL v2"); > > -- > > 1.9.1 > > > > > > _______________________________________________ > > linux-arm-kernel mailing list > > linux-arm-kernel@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [v5,6/6] usb: musb: Add support for MediaTek musb controller From: min.guo@mediatek.com Message-Id: <1554096924.19123.3.camel@mhfsdcap03> Date: Mon, 1 Apr 2019 13:35:24 +0800 To: Fabien Parent Cc: Bin Liu , Rob Herring , Mark Rutland , devicetree@vger.kernel.org, Yonglong Wu , hdegoede@redhat.com, tony@atomide.com, Greg Kroah-Hartman , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Matthias Brugger , Alan Stern , chunfeng.yun@mediatek.com, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org List-ID: SGkgRmFiaWVuIFBhcmVudCwKCk9uIFNhdCwgMjAxOS0wMy0zMCBhdCAwOTo1MiArMDEwMCwgRmFi aWVuIFBhcmVudCB3cm90ZToKPiBIaSBNaW4gR3VvLAo+IAo+IE9uIFR1ZSwgRmViIDE5LCAyMDE5 IGF0IDg6MzkgQU0gPG1pbi5ndW9AbWVkaWF0ZWsuY29tPiB3cm90ZToKPiA+Cj4gPiBGcm9tOiBN aW4gR3VvIDxtaW4uZ3VvQG1lZGlhdGVrLmNvbT4KPiA+Cj4gPiBUaGlzIGFkZHMgc3VwcG9ydCBm b3IgTWVkaWFUZWsgbXVzYiBjb250cm9sbGVyIGluCj4gPiBob3N0LCBwZXJpcGhlcmFsIGFuZCBv dGcgbW9kZS4KPiA+IFRoZXJlIGFyZSBzb21lIHF1aXJrIG9mIE1lZGlhVGVrIG11c2IgY29udHJv bGxlciwgc3VjaCBhczoKPiA+ICAtVzFDIGludGVycnVwdCBzdGF0dXMgcmVnaXN0ZXJzCj4gPiAg LVByaXZhdGUgZGF0YSB0b2dnbGUgcmVnaXN0ZXJzCj4gPiAgLU5vIGRlZGljYXRlZCBETUEgaW50 ZXJydXB0IGxpbmUKPiA+Cj4gPiBTaWduZWQtb2ZmLWJ5OiBNaW4gR3VvIDxtaW4uZ3VvQG1lZGlh dGVrLmNvbT4KPiA+IFNpZ25lZC1vZmYtYnk6IFlvbmdsb25nIFd1IDx5b25nbG9uZy53dUBtZWRp YXRlay5jb20+Cj4gPiAtLS0KPiA+IGNoYW5nZXMgaW4gdjU6Cj4gPiAxLiBSZXBsYWNlIG11c2Jf cmVhZGIoKSB3aXRoIG11c2JfY2xlYXJiKCkgdG8gY2xlYXIgY29tbW9uL3R4L3J4IHBlbmRpbmcg aW50ZXJydXB0cwo+ID4gMi4gTWFrZSBtdXNiX2NsZWFyYi93KCkgcmV0dXJuIHRoZSB2YWx1ZSBv ZiBtdXNiX3JlYWRiL3coKQo+ID4gMy4gQWRkIGRyaXZlciB0byBnZXQgY2hpbGQgbm9kZXMgb2Yg dXNiIGNvbm5lY3RvciBhbmQgZXh0Y29uIGRldmljZQo+ID4KPiA+IGNoYW5nZXMgaW4gdjQ6Cj4g PiAxLiBubyBjaGFuZ2VzCj4gPgo+ID4gY2hhbmdlcyBpbiB2MzoKPiA+IHN1Z2dlc3RlZCBieSBC aW46Cj4gPiAxLiBSZW1vdmUgJ3U4L3UxNiBkYXRhJyBwYXJhbWV0ZXIgaW4gY2xlYXJiL3coKSBo b29rcwo+ID4gMi4gUmVwbGFjZSBtdXNiX3JlYWRiL3coKSB3aXRoIG11c2JfY2xlYXJiL3coKSB0 byBjbGVhciBpbnRlcnJ1cHRzIHN0YXR1cwo+ID4KPiA+IGNoYW5nZXMgaW4gdjI6Cj4gPiBzdWdn ZXN0ZWQgYnkgQmluOgo+ID4gMS4gQWRkIHN1bW1hcml6ZSBvZiBNZWRpYVRlayBtdXNiIGNvbnRy b2xsZXIgZGlmZmVyZW5jZXMgaW4gdGhlIGNvbW1pdCBsb2cKPiA+IDIuIEFkZCAifHwgQ09NUElM RV9URVNUIiBpbiBLY29uZmlnCj4gPiAzLiBNb3ZlIE1lZGlhVGVrJ3MgcHJpdmF0ZSB0b2dnbGUg cmVnaXN0ZXJzIGZyb20gbXVzYl9yZWdzLmggdG8gbWVkaWF0ZWsuYwo+ID4gNC4gUmVwbGFjZSBt dXNiX3JlYWRsKCkgd2l0aCBtdXNiX3JlYWR3KCkgdG8gcmVhZCAxNmJpdCB0b2dnbGUgcmVnaXN0 ZXIKPiA+IC0tLQo+ID4gIGRyaXZlcnMvdXNiL211c2IvS2NvbmZpZyAgICB8ICAgOCArLQo+ID4g IGRyaXZlcnMvdXNiL211c2IvTWFrZWZpbGUgICB8ICAgMSArCj4gPiAgZHJpdmVycy91c2IvbXVz Yi9tZWRpYXRlay5jIHwgNjI5ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrCj4gPiAgMyBmaWxlcyBjaGFuZ2VkLCA2MzcgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlv bigtKQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL3VzYi9tdXNiL21lZGlhdGVrLmMK PiA+Cj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvbXVzYi9LY29uZmlnIGIvZHJpdmVycy91 c2IvbXVzYi9LY29uZmlnCj4gPiBpbmRleCBhZDA4ODk1Li5iNzJiN2MxIDEwMDY0NAo+ID4gLS0t IGEvZHJpdmVycy91c2IvbXVzYi9LY29uZmlnCj4gPiArKysgYi9kcml2ZXJzL3VzYi9tdXNiL0tj b25maWcKPiA+IEBAIC0xMTUsNiArMTE1LDEyIEBAIGNvbmZpZyBVU0JfTVVTQl9KWjQ3NDAKPiA+ ICAgICAgICAgZGVwZW5kcyBvbiBVU0JfTVVTQl9HQURHRVQKPiA+ICAgICAgICAgZGVwZW5kcyBv biBVU0JfT1RHX0JMQUNLTElTVF9IVUIKPiA+Cj4gPiArY29uZmlnIFVTQl9NVVNCX01FRElBVEVL Cj4gPiArICAgICAgIHRyaXN0YXRlICJNZWRpYVRlayBwbGF0Zm9ybXMiCj4gPiArICAgICAgIGRl cGVuZHMgb24gQVJDSF9NRURJQVRFSyB8fCBDT01QSUxFX1RFU1QKPiA+ICsgICAgICAgZGVwZW5k cyBvbiBOT1BfVVNCX1hDRUlWCj4gPiArICAgICAgIGRlcGVuZHMgb24gR0VORVJJQ19QSFkKPiA+ ICsKPiA+ICBjb25maWcgVVNCX01VU0JfQU0zMzVYX0NISUxECj4gPiAgICAgICAgIHRyaXN0YXRl Cj4gPgo+ID4gQEAgLTE0MSw3ICsxNDcsNyBAQCBjb25maWcgVVNCX1VYNTAwX0RNQQo+ID4KPiA+ ICBjb25maWcgVVNCX0lOVkVOVFJBX0RNQQo+ID4gICAgICAgICBib29sICdJbnZlbnRyYScKPiA+ IC0gICAgICAgZGVwZW5kcyBvbiBVU0JfTVVTQl9PTUFQMlBMVVMKPiA+ICsgICAgICAgZGVwZW5k cyBvbiBVU0JfTVVTQl9PTUFQMlBMVVMgfHwgVVNCX01VU0JfTUVESUFURUsKPiA+ICAgICAgICAg aGVscAo+ID4gICAgICAgICAgIEVuYWJsZSBETUEgdHJhbnNmZXJzIHVzaW5nIE1lbnRvcidzIGVu Z2luZS4KPiA+Cj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy91c2IvbXVzYi9NYWtlZmlsZSBiL2Ry aXZlcnMvdXNiL211c2IvTWFrZWZpbGUKPiA+IGluZGV4IDNhODhjNzkuLjYzZDgyZDAgMTAwNjQ0 Cj4gPiAtLS0gYS9kcml2ZXJzL3VzYi9tdXNiL01ha2VmaWxlCj4gPiArKysgYi9kcml2ZXJzL3Vz Yi9tdXNiL01ha2VmaWxlCj4gPiBAQCAtMjQsNiArMjQsNyBAQCBvYmotJChDT05GSUdfVVNCX01V U0JfREE4WFgpICAgICAgICAgICAgICAgICAgKz0gZGE4eHgubwo+ID4gIG9iai0kKENPTkZJR19V U0JfTVVTQl9VWDUwMCkgICAgICAgICAgICAgICAgICAgKz0gdXg1MDAubwo+ID4gIG9iai0kKENP TkZJR19VU0JfTVVTQl9KWjQ3NDApICAgICAgICAgICAgICAgICAgKz0gano0NzQwLm8KPiA+ICBv YmotJChDT05GSUdfVVNCX01VU0JfU1VOWEkpICAgICAgICAgICAgICAgICAgICs9IHN1bnhpLm8K PiA+ICtvYmotJChDT05GSUdfVVNCX01VU0JfTUVESUFURUspICAgICAgICAgICAgICAgICs9IG1l ZGlhdGVrLm8KPiA+Cj4gPgo+ID4gIG9iai0kKENPTkZJR19VU0JfTVVTQl9BTTMzNVhfQ0hJTEQp ICAgICAgICAgICAgKz0gbXVzYl9hbTMzNXgubwo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdXNi L211c2IvbWVkaWF0ZWsuYyBiL2RyaXZlcnMvdXNiL211c2IvbWVkaWF0ZWsuYwo+ID4gbmV3IGZp bGUgbW9kZSAxMDA2NDQKPiA+IGluZGV4IDAwMDAwMDAuLjk0NmI0NTMKPiA+IC0tLSAvZGV2L251 bGwKPiA+ICsrKyBiL2RyaXZlcnMvdXNiL211c2IvbWVkaWF0ZWsuYwo+ID4gQEAgLTAsMCArMSw2 MjkgQEAKPiA+ICsvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAo+ID4gKy8qCj4g PiArICogQ29weXJpZ2h0IChDKSAyMDE4IE1lZGlhVGVrIEluYy4KPiA+ICsgKgo+ID4gKyAqIEF1 dGhvcjoKPiA+ICsgKiAgTWluIEd1byA8bWluLmd1b0BtZWRpYXRlay5jb20+Cj4gPiArICogIFlv bmdsb25nIFd1IDx5b25nbG9uZy53dUBtZWRpYXRlay5jb20+Cj4gPiArICovCj4gPiArCj4gPiAr I2luY2x1ZGUgPGxpbnV4L2Nsay5oPgo+ID4gKyNpbmNsdWRlIDxsaW51eC9kbWEtbWFwcGluZy5o Pgo+ID4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KPiA+ICsjaW5jbHVkZSA8bGludXgvcGxh dGZvcm1fZGV2aWNlLmg+Cj4gPiArI2luY2x1ZGUgPGxpbnV4L3VzYi91c2JfcGh5X2dlbmVyaWMu aD4KPiA+ICsjaW5jbHVkZSAibXVzYl9jb3JlLmgiCj4gPiArI2luY2x1ZGUgIm11c2JfZG1hLmgi Cj4gPiArCj4gPiArI2RlZmluZSBVU0JfTDFJTlRTICAgICAweDAwYTAKPiA+ICsjZGVmaW5lIFVT Ql9MMUlOVE0gICAgIDB4MDBhNAo+ID4gKyNkZWZpbmUgTVRLX01VU0JfVFhGVU5DQUREUiAgICAw eDA0ODAKPiA+ICsKPiA+ICsvKiBNZWRpYVRlayBjb250cm9sbGVyIHRvZ2dsZSBlbmFibGUgYW5k IHN0YXR1cyByZWcgKi8KPiA+ICsjZGVmaW5lIE1VU0JfUlhUT0cgICAgICAgICAgICAgMHg4MAo+ ID4gKyNkZWZpbmUgTVVTQl9SWFRPR0VOICAgICAgICAgICAweDgyCj4gPiArI2RlZmluZSBNVVNC X1RYVE9HICAgICAgICAgICAgIDB4ODQKPiA+ICsjZGVmaW5lIE1VU0JfVFhUT0dFTiAgICAgICAg ICAgMHg4Ngo+ID4gKwo+ID4gKyNkZWZpbmUgVFhfSU5UX1NUQVRVUyAgICAgICAgICBCSVQoMCkK PiA+ICsjZGVmaW5lIFJYX0lOVF9TVEFUVVMgICAgICAgICAgQklUKDEpCj4gPiArI2RlZmluZSBV U0JDT01fSU5UX1NUQVRVUyAgICAgICAgICAgICAgQklUKDIpCj4gPiArI2RlZmluZSBETUFfSU5U X1NUQVRVUyAgICAgICAgIEJJVCgzKQo+ID4gKwo+ID4gKyNkZWZpbmUgRE1BX0lOVFJfU1RBVFVT X01TSyAgICAgICAgICAgIEdFTk1BU0soNywgMCkKPiA+ICsjZGVmaW5lIERNQV9JTlRSX1VOTUFT S19TRVRfTVNLICAgICAgICBHRU5NQVNLKDMxLCAyNCkKPiA+ICsKPiA+ICtlbnVtIG10a192YnVz X2lkX3N0YXRlIHsKPiA+ICsgICAgICAgTVRLX0lEX0ZMT0FUID0gMSwKPiA+ICsgICAgICAgTVRL X0lEX0dST1VORCwKPiA+ICsgICAgICAgTVRLX1ZCVVNfT0ZGLAo+ID4gKyAgICAgICBNVEtfVkJV U19WQUxJRCwKPiA+ICt9Owo+ID4gKwo+ID4gK3N0cnVjdCBtdGtfZ2x1ZSB7Cj4gPiArICAgICAg IHN0cnVjdCBkZXZpY2UgKmRldjsKPiA+ICsgICAgICAgc3RydWN0IG11c2IgKm11c2I7Cj4gPiAr ICAgICAgIHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKm11c2JfcGRldjsKPiA+ICsgICAgICAgc3Ry dWN0IHBsYXRmb3JtX2RldmljZSAqdXNiX3BoeTsKPiA+ICsgICAgICAgc3RydWN0IHBoeSAqcGh5 Owo+ID4gKyAgICAgICBzdHJ1Y3QgdXNiX3BoeSAqeGNlaXY7Cj4gPiArICAgICAgIGVudW0gcGh5 X21vZGUgcGh5X21vZGU7Cj4gPiArICAgICAgIHN0cnVjdCBjbGsgKm1haW47Cj4gPiArICAgICAg IHN0cnVjdCBjbGsgKm1jdTsKPiA+ICsgICAgICAgc3RydWN0IGNsayAqdW5pdnBsbDsKPiA+ICsg ICAgICAgc3RydWN0IHJlZ3VsYXRvciAqdmJ1czsKPiA+ICsgICAgICAgc3RydWN0IGV4dGNvbl9k ZXYgKmVkZXY7Cj4gPiArICAgICAgIHN0cnVjdCBub3RpZmllcl9ibG9jayB2YnVzX25iOwo+ID4g KyAgICAgICBzdHJ1Y3Qgbm90aWZpZXJfYmxvY2sgaWRfbmI7Cj4gPiArfTsKPiA+ICsKPiA+ICtz dGF0aWMgaW50IG10a19tdXNiX2Nsa3NfZ2V0KHN0cnVjdCBtdGtfZ2x1ZSAqZ2x1ZSkKPiA+ICt7 Cj4gPiArICAgICAgIHN0cnVjdCBkZXZpY2UgKmRldiA9IGdsdWUtPmRldjsKPiA+ICsKPiA+ICsg ICAgICAgZ2x1ZS0+bWFpbiA9IGRldm1fY2xrX2dldChkZXYsICJtYWluIik7Cj4gPiArICAgICAg IGlmIChJU19FUlIoZ2x1ZS0+bWFpbikpIHsKPiA+ICsgICAgICAgICAgICAgICBkZXZfZXJyKGRl diwgImZhaWwgdG8gZ2V0IG1haW4gY2xvY2tcbiIpOwo+ID4gKyAgICAgICAgICAgICAgIHJldHVy biBQVFJfRVJSKGdsdWUtPm1haW4pOwo+ID4gKyAgICAgICB9Cj4gPiArCj4gPiArICAgICAgIGds dWUtPm1jdSA9IGRldm1fY2xrX2dldChkZXYsICJtY3UiKTsKPiA+ICsgICAgICAgaWYgKElTX0VS UihnbHVlLT5tY3UpKSB7Cj4gPiArICAgICAgICAgICAgICAgZGV2X2VycihkZXYsICJmYWlsIHRv IGdldCBtY3UgY2xvY2tcbiIpOwo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBQVFJfRVJSKGds dWUtPm1jdSk7Cj4gPiArICAgICAgIH0KPiA+ICsKPiA+ICsgICAgICAgZ2x1ZS0+dW5pdnBsbCA9 IGRldm1fY2xrX2dldChkZXYsICJ1bml2cGxsIik7Cj4gPiArICAgICAgIGlmIChJU19FUlIoZ2x1 ZS0+dW5pdnBsbCkpIHsKPiA+ICsgICAgICAgICAgICAgICBkZXZfZXJyKGRldiwgImZhaWwgdG8g Z2V0IHVuaXZwbGwgY2xvY2tcbiIpOwo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBQVFJfRVJS KGdsdWUtPnVuaXZwbGwpOwo+ID4gKyAgICAgICB9Cj4gPiArCj4gPiArICAgICAgIHJldHVybiAw Owo+ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMgaW50IG10a19tdXNiX2Nsa3NfZW5hYmxlKHN0cnVj dCBtdGtfZ2x1ZSAqZ2x1ZSkKPiA+ICt7Cj4gPiArICAgICAgIGludCByZXQ7Cj4gPiArCj4gPiAr ICAgICAgIHJldCA9IGNsa19wcmVwYXJlX2VuYWJsZShnbHVlLT5tYWluKTsKPiA+ICsgICAgICAg aWYgKHJldCkgewo+ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIoZ2x1ZS0+ZGV2LCAiZmFpbGVk IHRvIGVuYWJsZSBtYWluIGNsb2NrXG4iKTsKPiA+ICsgICAgICAgICAgICAgICBnb3RvIGVycl9t YWluX2NsazsKPiA+ICsgICAgICAgfQo+ID4gKwo+ID4gKyAgICAgICByZXQgPSBjbGtfcHJlcGFy ZV9lbmFibGUoZ2x1ZS0+bWN1KTsKPiA+ICsgICAgICAgaWYgKHJldCkgewo+ID4gKyAgICAgICAg ICAgICAgIGRldl9lcnIoZ2x1ZS0+ZGV2LCAiZmFpbGVkIHRvIGVuYWJsZSBtY3UgY2xvY2tcbiIp Owo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZXJyX21jdV9jbGs7Cj4gPiArICAgICAgIH0KPiA+ ICsKPiA+ICsgICAgICAgcmV0ID0gY2xrX3ByZXBhcmVfZW5hYmxlKGdsdWUtPnVuaXZwbGwpOwo+ ID4gKyAgICAgICBpZiAocmV0KSB7Cj4gPiArICAgICAgICAgICAgICAgZGV2X2VycihnbHVlLT5k ZXYsICJmYWlsZWQgdG8gZW5hYmxlIHVuaXZwbGwgY2xvY2tcbiIpOwo+ID4gKyAgICAgICAgICAg ICAgIGdvdG8gZXJyX3VuaXZwbGxfY2xrOwo+ID4gKyAgICAgICB9Cj4gPiArCj4gPiArICAgICAg IHJldHVybiAwOwo+ID4gKwo+ID4gK2Vycl91bml2cGxsX2NsazoKPiA+ICsgICAgICAgY2xrX2Rp c2FibGVfdW5wcmVwYXJlKGdsdWUtPm1jdSk7Cj4gPiArZXJyX21jdV9jbGs6Cj4gPiArICAgICAg IGNsa19kaXNhYmxlX3VucHJlcGFyZShnbHVlLT5tYWluKTsKPiA+ICtlcnJfbWFpbl9jbGs6Cj4g PiArICAgICAgIHJldHVybiByZXQ7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyB2b2lkIG10a19t dXNiX2Nsa3NfZGlzYWJsZShzdHJ1Y3QgbXRrX2dsdWUgKmdsdWUpCj4gPiArewo+ID4gKyAgICAg ICBjbGtfZGlzYWJsZV91bnByZXBhcmUoZ2x1ZS0+dW5pdnBsbCk7Cj4gPiArICAgICAgIGNsa19k aXNhYmxlX3VucHJlcGFyZShnbHVlLT5tY3UpOwo+ID4gKyAgICAgICBjbGtfZGlzYWJsZV91bnBy ZXBhcmUoZ2x1ZS0+bWFpbik7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyB2b2lkIG10a19tdXNi X3NldF92YnVzKHN0cnVjdCBtdXNiICptdXNiLCBpbnQgaXNfb24pCj4gPiArewo+ID4gKyAgICAg ICBzdHJ1Y3QgZGV2aWNlICpkZXYgPSBtdXNiLT5jb250cm9sbGVyOwo+ID4gKyAgICAgICBzdHJ1 Y3QgbXRrX2dsdWUgKmdsdWUgPSBkZXZfZ2V0X2RydmRhdGEoZGV2LT5wYXJlbnQpOwo+ID4gKyAg ICAgICBpbnQgcmV0Owo+ID4gKwo+ID4gKyAgICAgICAvKiB2YnVzIGlzIG9wdGlvbmFsICovCj4g PiArICAgICAgIGlmICghZ2x1ZS0+dmJ1cykKPiA+ICsgICAgICAgICAgICAgICByZXR1cm47Cj4g PiArCj4gPiArICAgICAgIGRldl9kYmcobXVzYi0+Y29udHJvbGxlciwgIiVzLCBpc19vbj0lZFxy XG4iLCBfX2Z1bmNfXywgaXNfb24pOwo+ID4gKyAgICAgICBpZiAoaXNfb24pIHsKPiA+ICsgICAg ICAgICAgICAgICByZXQgPSByZWd1bGF0b3JfZW5hYmxlKGdsdWUtPnZidXMpOwo+ID4gKyAgICAg ICAgICAgICAgIGlmIChyZXQpIHsKPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGRldl9lcnIo Z2x1ZS0+ZGV2LCAiZmFpbCB0byBlbmFibGUgdmJ1cyByZWd1bGF0b3JcbiIpOwo+ID4gKyAgICAg ICAgICAgICAgICAgICAgICAgcmV0dXJuOwo+ID4gKyAgICAgICAgICAgICAgIH0KPiA+ICsgICAg ICAgfSBlbHNlIHsKPiA+ICsgICAgICAgICAgICAgICByZWd1bGF0b3JfZGlzYWJsZShnbHVlLT52 YnVzKTsKPiA+ICsgICAgICAgfQo+ID4gK30KPiA+ICsKPiA+ICsvKgo+ID4gKyAqIHN3aXRjaCB0 byBob3N0OiAtPiBNVEtfVkJVU19PRkYgLS0+IE1US19JRF9HUk9VTkQKPiA+ICsgKiBzd2l0Y2gg dG8gZGV2aWNlOiAtPiBNVEtfSURfRkxPQVQgLS0+IE1US19WQlVTX1ZBTElECj4gPiArICovCj4g PiArc3RhdGljIHZvaWQgbXRrX211c2Jfc2V0X21haWxib3goc3RydWN0IG10a19nbHVlICpnbHVl LAo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW51bSBtdGtfdmJ1c19pZF9z dGF0ZSBzdGF0dXMpCj4gPiArewo+ID4gKyAgICAgICBzdHJ1Y3QgbXVzYiAqbXVzYiA9IGdsdWUt Pm11c2I7Cj4gPiArICAgICAgIHU4IGRldmN0bCA9IDA7Cj4gPiArCj4gPiArICAgICAgIGRldl9k YmcoZ2x1ZS0+ZGV2LCAibWFpbGJveCBzdGF0ZSglZClcbiIsIHN0YXR1cyk7Cj4gPiArICAgICAg IHN3aXRjaCAoc3RhdHVzKSB7Cj4gPiArICAgICAgIGNhc2UgTVRLX0lEX0dST1VORDoKPiA+ICsg ICAgICAgICAgICAgICBwaHlfcG93ZXJfb24oZ2x1ZS0+cGh5KTsKPiA+ICsgICAgICAgICAgICAg ICBkZXZjdGwgPSByZWFkYihtdXNiLT5tcmVncyArIE1VU0JfREVWQ1RMKTsKPiA+ICsgICAgICAg ICAgICAgICBtdXNiLT54Y2Vpdi0+b3RnLT5zdGF0ZSA9IE9UR19TVEFURV9BX1dBSVRfVlJJU0U7 Cj4gPiArICAgICAgICAgICAgICAgbXRrX211c2Jfc2V0X3ZidXMobXVzYiwgMSk7Cj4gPiArICAg ICAgICAgICAgICAgZ2x1ZS0+cGh5X21vZGUgPSBQSFlfTU9ERV9VU0JfSE9TVDsKPiA+ICsgICAg ICAgICAgICAgICBwaHlfc2V0X21vZGUoZ2x1ZS0+cGh5LCBnbHVlLT5waHlfbW9kZSk7Cj4gPiAr ICAgICAgICAgICAgICAgZGV2Y3RsIHw9IE1VU0JfREVWQ1RMX1NFU1NJT047Cj4gPiArICAgICAg ICAgICAgICAgbXVzYl93cml0ZWIobXVzYi0+bXJlZ3MsIE1VU0JfREVWQ1RMLCBkZXZjdGwpOwo+ ID4gKyAgICAgICAgICAgICAgIE1VU0JfSFNUX01PREUobXVzYik7Cj4gPiArICAgICAgICAgICAg ICAgYnJlYWs7Cj4gPiArICAgICAgIC8qCj4gPiArICAgICAgICAqIE1US19JRF9GTE9BVCBwcm9j ZXNzIGlzIHRoZSBzYW1lIGFzIE1US19WQlVTX1ZBTElECj4gPiArICAgICAgICAqIGV4Y2VwdCB0 aGF0IHR1cm4gb2ZmIFZCVVMKPiA+ICsgICAgICAgICovCj4gPiArICAgICAgIGNhc2UgTVRLX0lE X0ZMT0FUOgo+ID4gKyAgICAgICAgICAgICAgIG10a19tdXNiX3NldF92YnVzKG11c2IsIDApOwo+ ID4gKyAgICAgICAgICAgICAgIC8qIGZhbGwgdGhyb3VnaCAqLwo+ID4gKyAgICAgICBjYXNlIE1U S19WQlVTX09GRjoKPiA+ICsgICAgICAgICAgICAgICBtdXNiLT54Y2Vpdi0+b3RnLT5zdGF0ZSA9 IE9UR19TVEFURV9CX0lETEU7Cj4gPiArICAgICAgICAgICAgICAgZGV2Y3RsICY9IH5NVVNCX0RF VkNUTF9TRVNTSU9OOwo+ID4gKyAgICAgICAgICAgICAgIG11c2Jfd3JpdGViKG11c2ItPm1yZWdz LCBNVVNCX0RFVkNUTCwgZGV2Y3RsKTsKPiA+ICsgICAgICAgICAgICAgICBwaHlfcG93ZXJfb2Zm KGdsdWUtPnBoeSk7Cj4gPiArICAgICAgICAgICAgICAgYnJlYWs7Cj4gPiArICAgICAgIGNhc2Ug TVRLX1ZCVVNfVkFMSUQ6Cj4gPiArICAgICAgICAgICAgICAgcGh5X3Bvd2VyX29uKGdsdWUtPnBo eSk7Cj4gPiArICAgICAgICAgICAgICAgZ2x1ZS0+cGh5X21vZGUgPSBQSFlfTU9ERV9VU0JfREVW SUNFOwo+ID4gKyAgICAgICAgICAgICAgIHBoeV9zZXRfbW9kZShnbHVlLT5waHksIGdsdWUtPnBo eV9tb2RlKTsKPiA+ICsgICAgICAgICAgICAgICBNVVNCX0RFVl9NT0RFKG11c2IpOwo+ID4gKyAg ICAgICAgICAgICAgIGJyZWFrOwo+ID4gKyAgICAgICBkZWZhdWx0Ogo+ID4gKyAgICAgICAgICAg ICAgIGRldl9lcnIoZ2x1ZS0+ZGV2LCAiaW52YWxpZCBzdGF0ZVxuIik7Cj4gPiArICAgICAgIH0K PiA+ICt9Cj4gPiArCj4gPiArc3RhdGljIGludCBtdGtfbXVzYl9pZF9ub3RpZmllcihzdHJ1Y3Qg bm90aWZpZXJfYmxvY2sgKm5iLAo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1 bnNpZ25lZCBsb25nIGV2ZW50LCB2b2lkICpwdHIpCj4gPiArewo+ID4gKyAgICAgICBzdHJ1Y3Qg bXRrX2dsdWUgKmdsdWUgPSBjb250YWluZXJfb2YobmIsIHN0cnVjdCBtdGtfZ2x1ZSwgaWRfbmIp Owo+ID4gKwo+ID4gKyAgICAgICBpZiAoZXZlbnQpCj4gPiArICAgICAgICAgICAgICAgbXRrX211 c2Jfc2V0X21haWxib3goZ2x1ZSwgTVRLX0lEX0dST1VORCk7Cj4gPiArICAgICAgIGVsc2UKPiA+ ICsgICAgICAgICAgICAgICBtdGtfbXVzYl9zZXRfbWFpbGJveChnbHVlLCBNVEtfSURfRkxPQVQp Owo+ID4gKwo+ID4gKyAgICAgICByZXR1cm4gTk9USUZZX0RPTkU7Cj4gPiArfQo+ID4gKwo+ID4g K3N0YXRpYyBpbnQgbXRrX211c2JfdmJ1c19ub3RpZmllcihzdHJ1Y3Qgbm90aWZpZXJfYmxvY2sg Km5iLAo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGxvbmcg ZXZlbnQsIHZvaWQgKnB0cikKPiA+ICt7Cj4gPiArICAgICAgIHN0cnVjdCBtdGtfZ2x1ZSAqZ2x1 ZSA9IGNvbnRhaW5lcl9vZihuYiwgc3RydWN0IG10a19nbHVlLCB2YnVzX25iKTsKPiA+ICsKPiA+ ICsgICAgICAgaWYgKGV2ZW50KQo+ID4gKyAgICAgICAgICAgICAgIG10a19tdXNiX3NldF9tYWls Ym94KGdsdWUsIE1US19WQlVTX1ZBTElEKTsKPiA+ICsgICAgICAgZWxzZQo+ID4gKyAgICAgICAg ICAgICAgIG10a19tdXNiX3NldF9tYWlsYm94KGdsdWUsIE1US19WQlVTX09GRik7Cj4gPiArCj4g PiArICAgICAgIHJldHVybiBOT1RJRllfRE9ORTsKPiA+ICt9Cj4gPiArCj4gPiArc3RhdGljIHZv aWQgbXRrX290Z19zd2l0Y2hfaW5pdChzdHJ1Y3QgbXRrX2dsdWUgKmdsdWUpCj4gPiArewo+ID4g KyAgICAgICBpbnQgcmV0Owo+ID4gKwo+ID4gKyAgICAgICAvKiBleHRjb24gaXMgb3B0aW9uYWwg Ki8KPiA+ICsgICAgICAgaWYgKCFnbHVlLT5lZGV2KQo+ID4gKyAgICAgICAgICAgICAgIHJldHVy bjsKPiA+ICsKPiA+ICsgICAgICAgZ2x1ZS0+dmJ1c19uYi5ub3RpZmllcl9jYWxsID0gbXRrX211 c2JfdmJ1c19ub3RpZmllcjsKPiA+ICsgICAgICAgcmV0ID0gZGV2bV9leHRjb25fcmVnaXN0ZXJf bm90aWZpZXIoZ2x1ZS0+ZGV2LCBnbHVlLT5lZGV2LCBFWFRDT05fVVNCLAo+ID4gKyAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmZ2x1ZS0+dmJ1c19uYik7Cj4gPiAr ICAgICAgIGlmIChyZXQgPCAwKQo+ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIoZ2x1ZS0+ZGV2 LCAiZmFpbGVkIHRvIHJlZ2lzdGVyIG5vdGlmaWVyIGZvciBVU0JcbiIpOwo+ID4gKwo+ID4gKyAg ICAgICBnbHVlLT5pZF9uYi5ub3RpZmllcl9jYWxsID0gbXRrX211c2JfaWRfbm90aWZpZXI7Cj4g PiArICAgICAgIHJldCA9IGRldm1fZXh0Y29uX3JlZ2lzdGVyX25vdGlmaWVyKGdsdWUtPmRldiwg Z2x1ZS0+ZWRldiwKPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgRVhUQ09OX1VTQl9IT1NULCAmZ2x1ZS0+aWRfbmIpOwo+ID4gKyAgICAgICBpZiAocmV0IDwg MCkKPiA+ICsgICAgICAgICAgICAgICBkZXZfZXJyKGdsdWUtPmRldiwgImZhaWxlZCB0byByZWdp c3RlciBub3RpZmllciBmb3IgVVNCLUhPU1RcbiIpOwo+ID4gKwo+ID4gKyAgICAgICBkZXZfZGJn KGdsdWUtPmRldiwgIkVYVENPTl9VU0I6ICVkLCBFWFRDT05fVVNCX0hPU1Q6ICVkXG4iLAo+ID4g KyAgICAgICAgICAgICAgIGV4dGNvbl9nZXRfc3RhdGUoZ2x1ZS0+ZWRldiwgRVhUQ09OX1VTQiks Cj4gPiArICAgICAgICAgICAgICAgZXh0Y29uX2dldF9zdGF0ZShnbHVlLT5lZGV2LCBFWFRDT05f VVNCX0hPU1QpKTsKPiA+ICsKPiA+ICsgICAgICAgLyogZGVmYXVsdCBhcyBob3N0LCBzd2l0Y2gg dG8gZGV2aWNlIG1vZGUgaWYgbmVlZGVkICovCj4gPiArICAgICAgIGlmIChleHRjb25fZ2V0X3N0 YXRlKGdsdWUtPmVkZXYsIEVYVENPTl9VU0JfSE9TVCkgPT0gZmFsc2UpCj4gPiArICAgICAgICAg ICAgICAgbXRrX211c2Jfc2V0X21haWxib3goZ2x1ZSwgTVRLX0lEX0ZMT0FUKTsKPiA+ICsgICAg ICAgaWYgKGV4dGNvbl9nZXRfc3RhdGUoZ2x1ZS0+ZWRldiwgRVhUQ09OX1VTQikgPT0gdHJ1ZSkK PiA+ICsgICAgICAgICAgICAgICBtdGtfbXVzYl9zZXRfbWFpbGJveChnbHVlLCBNVEtfVkJVU19W QUxJRCk7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyBpcnFyZXR1cm5fdCBnZW5lcmljX2ludGVy cnVwdChpbnQgaXJxLCB2b2lkICpfX2hjaSkKPiA+ICt7Cj4gPiArICAgICAgIHVuc2lnbmVkIGxv bmcgZmxhZ3M7Cj4gPiArICAgICAgIGlycXJldHVybl90IHJldHZhbCA9IElSUV9OT05FOwo+ID4g KyAgICAgICBzdHJ1Y3QgbXVzYiAqbXVzYiA9IF9faGNpOwo+ID4gKwo+ID4gKyAgICAgICBzcGlu X2xvY2tfaXJxc2F2ZSgmbXVzYi0+bG9jaywgZmxhZ3MpOwo+ID4gKyAgICAgICBtdXNiLT5pbnRf dXNiID0gbXVzYl9jbGVhcmIobXVzYi0+bXJlZ3MsIE1VU0JfSU5UUlVTQik7Cj4gPiArICAgICAg IG11c2ItPmludF9yeCA9IG11c2JfY2xlYXJ3KG11c2ItPm1yZWdzLCBNVVNCX0lOVFJSWCk7Cj4g PiArICAgICAgIG11c2ItPmludF90eCA9IG11c2JfY2xlYXJ3KG11c2ItPm1yZWdzLCBNVVNCX0lO VFJUWCk7Cj4gPiArCj4gPiArICAgICAgIGlmIChtdXNiLT5pbnRfdXNiIHx8IG11c2ItPmludF90 eCB8fCBtdXNiLT5pbnRfcngpCj4gPiArICAgICAgICAgICAgICAgcmV0dmFsID0gbXVzYl9pbnRl cnJ1cHQobXVzYik7Cj4gPiArCj4gPiArICAgICAgIHNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJm11 c2ItPmxvY2ssIGZsYWdzKTsKPiA+ICsKPiA+ICsgICAgICAgcmV0dXJuIHJldHZhbDsKPiA+ICt9 Cj4gPiArCj4gPiArc3RhdGljIGlycXJldHVybl90IG10a19tdXNiX2ludGVycnVwdChpbnQgaXJx LCB2b2lkICpkZXZfaWQpCj4gPiArewo+ID4gKyAgICAgICBpcnFyZXR1cm5fdCByZXR2YWwgPSBJ UlFfTk9ORTsKPiA+ICsgICAgICAgc3RydWN0IG11c2IgKm11c2IgPSAoc3RydWN0IG11c2IgKilk ZXZfaWQ7Cj4gPiArICAgICAgIHUzMiBsMV9pbnRzOwo+ID4gKwo+ID4gKyAgICAgICBsMV9pbnRz ID0gbXVzYl9yZWFkbChtdXNiLT5tcmVncywgVVNCX0wxSU5UUykgJgo+ID4gKyAgICAgICAgICAg ICAgICAgICAgICAgbXVzYl9yZWFkbChtdXNiLT5tcmVncywgVVNCX0wxSU5UTSk7Cj4gPiArCj4g PiArICAgICAgIGlmIChsMV9pbnRzICYgKFRYX0lOVF9TVEFUVVMgfCBSWF9JTlRfU1RBVFVTIHwg VVNCQ09NX0lOVF9TVEFUVVMpKQo+ID4gKyAgICAgICAgICAgICAgIHJldHZhbCA9IGdlbmVyaWNf aW50ZXJydXB0KGlycSwgbXVzYik7Cj4gPiArCj4gPiArI2lmIGRlZmluZWQoQ09ORklHX1VTQl9J TlZFTlRSQV9ETUEpCj4gPiArICAgICAgIGlmIChsMV9pbnRzICYgRE1BX0lOVF9TVEFUVVMpCj4g PiArICAgICAgICAgICAgICAgcmV0dmFsID0gZG1hX2NvbnRyb2xsZXJfaXJxKGlycSwgbXVzYi0+ ZG1hX2NvbnRyb2xsZXIpOwo+ID4gKyNlbmRpZgo+ID4gKyAgICAgICByZXR1cm4gcmV0dmFsOwo+ ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMgdTMyIG10a19tdXNiX2J1c2N0bF9vZmZzZXQodTggZXBu dW0sIHUxNiBvZmZzZXQpCj4gPiArewo+ID4gKyAgICAgICByZXR1cm4gTVRLX01VU0JfVFhGVU5D QUREUiArIG9mZnNldCArIDggKiBlcG51bTsKPiA+ICt9Cj4gPiArCj4gPiArc3RhdGljIHU4IG10 a19tdXNiX2NsZWFyYih2b2lkIF9faW9tZW0gKmFkZHIsIHVuc2lnbmVkIGludCBvZmZzZXQpCj4g PiArewo+ID4gKyAgICAgICB1OCBkYXRhOwo+ID4gKwo+ID4gKyAgICAgICAvKiBXMUMgKi8KPiA+ ICsgICAgICAgZGF0YSA9IG11c2JfcmVhZGIoYWRkciwgb2Zmc2V0KTsKPiA+ICsgICAgICAgbXVz Yl93cml0ZWIoYWRkciwgb2Zmc2V0LCBkYXRhKTsKPiA+ICsgICAgICAgcmV0dXJuIGRhdGE7Cj4g PiArfQo+ID4gKwo+ID4gK3N0YXRpYyB1MTYgbXRrX211c2JfY2xlYXJ3KHZvaWQgX19pb21lbSAq YWRkciwgdW5zaWduZWQgaW50IG9mZnNldCkKPiA+ICt7Cj4gPiArICAgICAgIHUxNiBkYXRhOwo+ ID4gKwo+ID4gKyAgICAgICAvKiBXMUMgKi8KPiA+ICsgICAgICAgZGF0YSA9IG11c2JfcmVhZHco YWRkciwgb2Zmc2V0KTsKPiA+ICsgICAgICAgbXVzYl93cml0ZXcoYWRkciwgb2Zmc2V0LCBkYXRh KTsKPiA+ICsgICAgICAgcmV0dXJuIGRhdGE7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyBpbnQg bXRrX211c2JfaW5pdChzdHJ1Y3QgbXVzYiAqbXVzYikKPiA+ICt7Cj4gPiArICAgICAgIHN0cnVj dCBkZXZpY2UgKmRldiA9IG11c2ItPmNvbnRyb2xsZXI7Cj4gPiArICAgICAgIHN0cnVjdCBtdGtf Z2x1ZSAqZ2x1ZSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYtPnBhcmVudCk7Cj4gPiArICAgICAgIGlu dCByZXQ7Cj4gPiArCj4gPiArICAgICAgIGdsdWUtPm11c2IgPSBtdXNiOwo+ID4gKyAgICAgICBt dXNiLT5waHkgPSBnbHVlLT5waHk7Cj4gPiArICAgICAgIG11c2ItPnhjZWl2ID0gZ2x1ZS0+eGNl aXY7Cj4gPiArICAgICAgIG11c2ItPmlzX2hvc3QgPSBmYWxzZTsKPiA+ICsgICAgICAgbXVzYi0+ aXNyID0gbXRrX211c2JfaW50ZXJydXB0Owo+ID4gKyAgICAgICByZXQgPSBwaHlfaW5pdChnbHVl LT5waHkpOwo+ID4gKyAgICAgICBpZiAocmV0KQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBy ZXQ7Cj4gPiArCj4gPiArICAgICAgIHJldCA9IHBoeV9wb3dlcl9vbihnbHVlLT5waHkpOwo+ID4g KyAgICAgICBpZiAocmV0KSB7Cj4gPiArICAgICAgICAgICAgICAgcGh5X2V4aXQoZ2x1ZS0+cGh5 KTsKPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gcmV0Owo+ID4gKyAgICAgICB9Cj4gPiArCj4g PiArICAgICAgIHBoeV9zZXRfbW9kZShnbHVlLT5waHksIGdsdWUtPnBoeV9tb2RlKTsKPiA+ICsK PiA+ICsjaWYgZGVmaW5lZChDT05GSUdfVVNCX0lOVkVOVFJBX0RNQSkKPiA+ICsgICAgICAgbXVz Yl93cml0ZWwobXVzYi0+bXJlZ3MsIE1VU0JfSFNETUFfSU5UUiwKPiA+ICsgICAgICAgICAgICAg ICAgICAgRE1BX0lOVFJfU1RBVFVTX01TSyB8IERNQV9JTlRSX1VOTUFTS19TRVRfTVNLKTsKPiA+ ICsjZW5kaWYKPiA+ICsgICAgICAgbXVzYl93cml0ZWwobXVzYi0+bXJlZ3MsIFVTQl9MMUlOVE0s IFRYX0lOVF9TVEFUVVMgfCBSWF9JTlRfU1RBVFVTIHwKPiA+ICsgICAgICAgICAgICAgICAgICAg VVNCQ09NX0lOVF9TVEFUVVMgfCBETUFfSU5UX1NUQVRVUyk7Cj4gPiArICAgICAgIHJldHVybiAw Owo+ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMgdTE2IG10a19tdXNiX2dldF90b2dnbGUoc3RydWN0 IG11c2JfcWggKnFoLCBpbnQgaXNfb3V0KQo+ID4gK3sKPiA+ICsgICAgICAgc3RydWN0IG11c2Ig Km11c2IgPSBxaC0+aHdfZXAtPm11c2I7Cj4gPiArICAgICAgIHU4IGVwbnVtID0gcWgtPmh3X2Vw LT5lcG51bTsKPiA+ICsgICAgICAgdTE2IHRvZ2dsZTsKPiA+ICsKPiA+ICsgICAgICAgaWYgKGlz X291dCkKPiA+ICsgICAgICAgICAgICAgICB0b2dnbGUgPSBtdXNiX3JlYWR3KG11c2ItPm1yZWdz LCBNVVNCX1RYVE9HKTsKPiA+ICsgICAgICAgZWxzZQo+ID4gKyAgICAgICAgICAgICAgIHRvZ2ds ZSA9IG11c2JfcmVhZHcobXVzYi0+bXJlZ3MsIE1VU0JfUlhUT0cpOwo+ID4gKwo+ID4gKyAgICAg ICByZXR1cm4gdG9nZ2xlICYgKDEgPDwgZXBudW0pOwo+ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMg dTE2IG10a19tdXNiX3NldF90b2dnbGUoc3RydWN0IG11c2JfcWggKnFoLCBpbnQgaXNfb3V0LCBz dHJ1Y3QgdXJiICp1cmIpCj4gPiArewo+ID4gKyAgICAgICBzdHJ1Y3QgbXVzYiAqbXVzYiA9IHFo LT5od19lcC0+bXVzYjsKPiA+ICsgICAgICAgdTggZXBudW0gPSBxaC0+aHdfZXAtPmVwbnVtOwo+ ID4gKyAgICAgICB1MTYgdG9nZ2xlOwo+ID4gKwo+ID4gKyAgICAgICB0b2dnbGUgPSB1c2JfZ2V0 dG9nZ2xlKHVyYi0+ZGV2LCBxaC0+ZXBudW0sIGlzX291dCk7Cj4gPiArCj4gPiArICAgICAgIGlm IChpc19vdXQpIHsKPiA+ICsgICAgICAgICAgICAgICBtdXNiX3dyaXRldyhtdXNiLT5tcmVncywg TVVTQl9UWFRPR0VOLCAoMSA8PCBlcG51bSkpOwo+ID4gKyAgICAgICAgICAgICAgIG11c2Jfd3Jp dGV3KG11c2ItPm1yZWdzLCBNVVNCX1RYVE9HLCAodG9nZ2xlIDw8IGVwbnVtKSk7Cj4gPiArICAg ICAgIH0gZWxzZSB7Cj4gPiArICAgICAgICAgICAgICAgbXVzYl93cml0ZXcobXVzYi0+bXJlZ3Ms IE1VU0JfUlhUT0dFTiwgKDEgPDwgZXBudW0pKTsKPiA+ICsgICAgICAgICAgICAgICBtdXNiX3dy aXRldyhtdXNiLT5tcmVncywgTVVTQl9SWFRPRywgKHRvZ2dsZSA8PCBlcG51bSkpOwo+ID4gKyAg ICAgICB9Cj4gPiArCj4gPiArICAgICAgIHJldHVybiAwOwo+ID4gK30KPiA+ICsKPiA+ICtzdGF0 aWMgaW50IG10a19tdXNiX3NldF9tb2RlKHN0cnVjdCBtdXNiICptdXNiLCB1OCBtb2RlKQo+ID4g K3sKPiA+ICsgICAgICAgc3RydWN0IGRldmljZSAqZGV2ID0gbXVzYi0+Y29udHJvbGxlcjsKPiA+ ICsgICAgICAgc3RydWN0IG10a19nbHVlICpnbHVlID0gZGV2X2dldF9kcnZkYXRhKGRldi0+cGFy ZW50KTsKPiA+ICsgICAgICAgZW51bSBwaHlfbW9kZSBuZXdfbW9kZTsKPiA+ICsKPiA+ICsgICAg ICAgc3dpdGNoIChtb2RlKSB7Cj4gPiArICAgICAgIGNhc2UgTVVTQl9IT1NUOgo+ID4gKyAgICAg ICAgICAgICAgIG5ld19tb2RlID0gUEhZX01PREVfVVNCX0hPU1Q7Cj4gPiArICAgICAgICAgICAg ICAgbXRrX211c2Jfc2V0X3ZidXMobXVzYiwgMSk7Cj4gPiArICAgICAgICAgICAgICAgYnJlYWs7 Cj4gPiArICAgICAgIGNhc2UgTVVTQl9QRVJJUEhFUkFMOgo+ID4gKyAgICAgICAgICAgICAgIG5l d19tb2RlID0gUEhZX01PREVfVVNCX0RFVklDRTsKPiA+ICsgICAgICAgICAgICAgICBicmVhazsK PiA+ICsgICAgICAgY2FzZSBNVVNCX09URzoKPiA+ICsgICAgICAgICAgICAgICBuZXdfbW9kZSA9 IFBIWV9NT0RFX1VTQl9IT1NUOwo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOwo+ID4gKyAgICAg ICBkZWZhdWx0Ogo+ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIobXVzYi0+Y29udHJvbGxlci0+ cGFyZW50LAo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgIkVycm9yIHJlcXVlc3RlZCBtb2Rl IG5vdCBzdXBwb3J0ZWQgYnkgdGhpcyBrZXJuZWxcbiIpOwo+ID4gKyAgICAgICAgICAgICAgIHJl dHVybiAtRUlOVkFMOwo+ID4gKyAgICAgICB9Cj4gPiArICAgICAgIGlmIChnbHVlLT5waHlfbW9k ZSA9PSBuZXdfbW9kZSkKPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMDsKPiA+ICsKPiA+ICsg ICAgICAgbXRrX211c2Jfc2V0X21haWxib3goZ2x1ZSwgTVRLX0lEX0dST1VORCk7Cj4gPiArICAg ICAgIHJldHVybiAwOwo+ID4gK30KPiA+ICsKPiA+ICtzdGF0aWMgaW50IG10a19tdXNiX2V4aXQo c3RydWN0IG11c2IgKm11c2IpCj4gPiArewo+ID4gKyAgICAgICBzdHJ1Y3QgZGV2aWNlICpkZXYg PSBtdXNiLT5jb250cm9sbGVyOwo+ID4gKyAgICAgICBzdHJ1Y3QgbXRrX2dsdWUgKmdsdWUgPSBk ZXZfZ2V0X2RydmRhdGEoZGV2LT5wYXJlbnQpOwo+ID4gKwo+ID4gKyAgICAgICBwaHlfcG93ZXJf b2ZmKGdsdWUtPnBoeSk7Cj4gPiArICAgICAgIHBoeV9leGl0KGdsdWUtPnBoeSk7Cj4gPiArICAg ICAgIG10a19tdXNiX2Nsa3NfZGlzYWJsZShnbHVlKTsKPiA+ICsKPiA+ICsgICAgICAgcG1fcnVu dGltZV9wdXRfc3luYyhkZXYpOwo+ID4gKyAgICAgICBwbV9ydW50aW1lX2Rpc2FibGUoZGV2KTsK PiA+ICsgICAgICAgcmV0dXJuIDA7Cj4gPiArfQo+ID4gKwo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1 Y3QgbXVzYl9wbGF0Zm9ybV9vcHMgbXRrX211c2Jfb3BzID0gewo+ID4gKyAgICAgICAucXVpcmtz ID0gTVVTQl9ETUFfSU5WRU5UUkEsCj4gPiArICAgICAgIC5pbml0ID0gbXRrX211c2JfaW5pdCwK PiA+ICsgICAgICAgLmdldF90b2dnbGUgPSBtdGtfbXVzYl9nZXRfdG9nZ2xlLAo+ID4gKyAgICAg ICAuc2V0X3RvZ2dsZSA9IG10a19tdXNiX3NldF90b2dnbGUsCj4gPiArICAgICAgIC5leGl0ID0g bXRrX211c2JfZXhpdCwKPiA+ICsjaWZkZWYgQ09ORklHX1VTQl9JTlZFTlRSQV9ETUEKPiA+ICsg ICAgICAgLmRtYV9pbml0ID0gbXVzYmhzX2RtYV9jb250cm9sbGVyX2NyZWF0ZV9ub2lycSwKPiA+ ICsgICAgICAgLmRtYV9leGl0ID0gbXVzYmhzX2RtYV9jb250cm9sbGVyX2Rlc3Ryb3ksCj4gPiAr I2VuZGlmCj4gPiArICAgICAgIC5jbGVhcmIgPSBtdGtfbXVzYl9jbGVhcmIsCj4gPiArICAgICAg IC5jbGVhcncgPSBtdGtfbXVzYl9jbGVhcncsCj4gPiArICAgICAgIC5idXNjdGxfb2Zmc2V0ID0g bXRrX211c2JfYnVzY3RsX29mZnNldCwKPiA+ICsgICAgICAgLnNldF9tb2RlID0gbXRrX211c2Jf c2V0X21vZGUsCj4gPiArICAgICAgIC5zZXRfdmJ1cyA9IG10a19tdXNiX3NldF92YnVzLAo+ID4g K307Cj4gPiArCj4gPiArI2RlZmluZSBNVEtfTVVTQl9NQVhfRVBfTlVNICAgIDgKPiA+ICsjZGVm aW5lIE1US19NVVNCX1JBTV9CSVRTICAgICAgMTEKPiA+ICsKPiA+ICtzdGF0aWMgc3RydWN0IG11 c2JfZmlmb19jZmcgbXRrX211c2JfbW9kZV9jZmdbXSA9IHsKPiA+ICsgICAgICAgeyAuaHdfZXBf bnVtID0gMSwgLnN0eWxlID0gRklGT19UWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAg ICAgeyAuaHdfZXBfbnVtID0gMSwgLnN0eWxlID0gRklGT19SWCwgLm1heHBhY2tldCA9IDUxMiwg fSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0gMiwgLnN0eWxlID0gRklGT19UWCwgLm1heHBh Y2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0gMiwgLnN0eWxlID0gRklG T19SWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0gMywg LnN0eWxlID0gRklGT19UWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAuaHdf ZXBfbnVtID0gMywgLnN0eWxlID0gRklGT19SWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsg ICAgICAgeyAuaHdfZXBfbnVtID0gNCwgLnN0eWxlID0gRklGT19UWCwgLm1heHBhY2tldCA9IDUx MiwgfSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0gNCwgLnN0eWxlID0gRklGT19SWCwgLm1h eHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0gNSwgLnN0eWxlID0g RklGT19UWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAuaHdfZXBfbnVtID0g NSwgLnN0eWxlID0gRklGT19SWCwgLm1heHBhY2tldCA9IDUxMiwgfSwKPiA+ICsgICAgICAgeyAu aHdfZXBfbnVtID0gNiwgLnN0eWxlID0gRklGT19UWCwgLm1heHBhY2tldCA9IDEwMjQsIH0sCj4g PiArICAgICAgIHsgLmh3X2VwX251bSA9IDYsIC5zdHlsZSA9IEZJRk9fUlgsIC5tYXhwYWNrZXQg PSAxMDI0LCB9LAo+ID4gKyAgICAgICB7IC5od19lcF9udW0gPSA3LCAuc3R5bGUgPSBGSUZPX1RY LCAubWF4cGFja2V0ID0gNTEyLCB9LAo+ID4gKyAgICAgICB7IC5od19lcF9udW0gPSA3LCAuc3R5 bGUgPSBGSUZPX1JYLCAubWF4cGFja2V0ID0gNjQsIH0sCj4gPiArfTsKPiA+ICsKPiA+ICtzdGF0 aWMgY29uc3Qgc3RydWN0IG11c2JfaGRyY19jb25maWcgbXRrX211c2JfaGRyY19jb25maWcgPSB7 Cj4gPiArICAgICAgIC5maWZvX2NmZyA9IG10a19tdXNiX21vZGVfY2ZnLAo+ID4gKyAgICAgICAu Zmlmb19jZmdfc2l6ZSA9IEFSUkFZX1NJWkUobXRrX211c2JfbW9kZV9jZmcpLAo+ID4gKyAgICAg ICAubXVsdGlwb2ludCA9IHRydWUsCj4gPiArICAgICAgIC5keW5fZmlmbyA9IHRydWUsCj4gPiAr ICAgICAgIC5udW1fZXBzID0gTVRLX01VU0JfTUFYX0VQX05VTSwKPiA+ICsgICAgICAgLnJhbV9i aXRzID0gTVRLX01VU0JfUkFNX0JJVFMsCj4gPiArfTsKPiA+ICsKPiA+ICtzdGF0aWMgY29uc3Qg c3RydWN0IHBsYXRmb3JtX2RldmljZV9pbmZvIG10a19kZXZfaW5mbyA9IHsKPiA+ICsgICAgICAg Lm5hbWUgPSAibXVzYi1oZHJjIiwKPiA+ICsgICAgICAgLmlkID0gUExBVEZPUk1fREVWSURfQVVU TywKPiA+ICsgICAgICAgLmRtYV9tYXNrID0gRE1BX0JJVF9NQVNLKDMyKSwKPiA+ICt9Owo+ID4g Kwo+ID4gK3N0YXRpYyBpbnQgbXRrX211c2JfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAq cGRldikKPiA+ICt7Cj4gPiArICAgICAgIHN0cnVjdCBtdXNiX2hkcmNfcGxhdGZvcm1fZGF0YSAq cGRhdGE7Cj4gPiArICAgICAgIHN0cnVjdCBtdGtfZ2x1ZSAqZ2x1ZTsKPiA+ICsgICAgICAgc3Ry dWN0IHBsYXRmb3JtX2RldmljZV9pbmZvIHBpbmZvOwo+ID4gKyAgICAgICBzdHJ1Y3QgZGV2aWNl ICpkZXYgPSAmcGRldi0+ZGV2Owo+ID4gKyAgICAgICBzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0g ZGV2LT5vZl9ub2RlOwo+ID4gKyAgICAgICBzdHJ1Y3QgZGV2aWNlX25vZGUgKmNoaWxkLCAqZXh0 Y29uX25vZGU7Cj4gPiArICAgICAgIGludCByZXQgPSAtRU5PTUVNOwo+ID4gKwo+ID4gKyAgICAg ICBnbHVlID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpnbHVlKSwgR0ZQX0tFUk5FTCk7Cj4g PiArICAgICAgIGlmICghZ2x1ZSkKPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gLUVOT01FTTsK PiA+ICsKPiA+ICsgICAgICAgZ2x1ZS0+ZGV2ID0gZGV2Owo+ID4gKyAgICAgICBwZGF0YSA9IGRl dm1fa3phbGxvYyhkZXYsIHNpemVvZigqcGRhdGEpLCBHRlBfS0VSTkVMKTsKPiA+ICsgICAgICAg aWYgKCFwZGF0YSkKPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gLUVOT01FTTsKPiA+ICsKPiA+ ICsgICAgICAgcmV0ID0gbXRrX211c2JfY2xrc19nZXQoZ2x1ZSk7Cj4gPiArICAgICAgIGlmIChy ZXQpCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHJldDsKPiA+ICsKPiA+ICsgICAgICAgcGRh dGEtPmNvbmZpZyA9ICZtdGtfbXVzYl9oZHJjX2NvbmZpZzsKPiA+ICsgICAgICAgcGRhdGEtPnBs YXRmb3JtX29wcyA9ICZtdGtfbXVzYl9vcHM7Cj4gPiArCj4gPiArICAgICAgIGdsdWUtPnZidXMg PSBkZXZtX3JlZ3VsYXRvcl9nZXQoZGV2LCAidmJ1cyIpOwo+ID4gKyAgICAgICBpZiAoSVNfRVJS KGdsdWUtPnZidXMpKSB7Cj4gPiArICAgICAgICAgICAgICAgZGV2X2VycihkZXYsICJmYWlsIHRv IGdldCB2YnVzXG4iKTsKPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gUFRSX0VSUihnbHVlLT52 YnVzKTsKPiA+ICsgICAgICAgfQo+ID4gKwo+ID4gKyAgICAgICBjaGlsZCA9IG9mX2dldF9jaGls ZF9ieV9uYW1lKG5wLCAiY29ubmVjdG9yIik7Cj4gPiArICAgICAgIGlmICghY2hpbGQpIHsKPiA+ ICsgICAgICAgICAgICAgICBkZXZfZXJyKGRldiwgImZhaWxlZCB0byBmaW5kIHVzYiBjb25uZWN0 b3Igbm9kZVxuIik7Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIEVSUl9QVFIoLUVOT0RFVik7 Cj4gCj4gVGhlICdwcm9iZScgZnVuY3Rpb24gaXMgcmV0dXJuaW5nIGFuICdpbnQnIGFuZCBub3Qg YSBwb2ludGVyLiBUaGlzCj4gbGluZSBzaG91bGQgdHJpZ2dlciBhIHdhcm5pbmcuCk9LLCB0aGFu a3MuIAoKPiA+ICsgICAgICAgfQo+ID4gKwo+ID4gKyAgICAgICBleHRjb25fbm9kZSA9IG9mX3Bh cnNlX3BoYW5kbGUoY2hpbGQsICJleHRjb24iLCAwKTsKPiA+ICsgICAgICAgaWYgKCFleHRjb25f bm9kZSkgewo+ID4gKyAgICAgICAgICAgICAgIGRldl9lcnIoZGV2LCAiZmFpbGVkIHRvIGdldCBl eHRjb24gcGhhbmRsZSIpOwo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBFUlJfUFRSKC1FTk9E RVYpOwo+IAo+IFNhbWUgaGVyZQpPSywgdGhhbmtzLiAKCj4gPiArICAgICAgIH0KPiA+ICsKPiA+ ICsgICAgICAgZ2x1ZS0+ZWRldiA9IGV4dGNvbl9maW5kX2VkZXZfYnlfbm9kZShleHRjb25fbm9k ZSk7Cj4gPiArICAgICAgIGlmIChJU19FUlIoZ2x1ZS0+ZWRldikpIHsKPiA+ICsgICAgICAgICAg ICAgICBkZXZfZXJyKGRldiwgImZhaWwgdG8gZ2V0IGV4dGNvblxuIik7Cj4gPiArICAgICAgICAg ICAgICAgcmV0dXJuIFBUUl9FUlIoZ2x1ZS0+ZWRldik7Cj4gPiArICAgICAgIH0KPiA+ICsKPiA+ ICsgICAgICAgcGRhdGEtPm1vZGUgPSB1c2JfZ2V0X2RyX21vZGUoZGV2KTsKPiA+ICsgICAgICAg c3dpdGNoIChwZGF0YS0+bW9kZSkgewo+ID4gKyAgICAgICBjYXNlIFVTQl9EUl9NT0RFX0hPU1Q6 Cj4gPiArICAgICAgICAgICAgICAgZ2x1ZS0+cGh5X21vZGUgPSBQSFlfTU9ERV9VU0JfSE9TVDsK PiA+ICsgICAgICAgICAgICAgICBicmVhazsKPiA+ICsgICAgICAgY2FzZSBVU0JfRFJfTU9ERV9Q RVJJUEhFUkFMOgo+ID4gKyAgICAgICAgICAgICAgIGdsdWUtPnBoeV9tb2RlID0gUEhZX01PREVf VVNCX0RFVklDRTsKPiA+ICsgICAgICAgICAgICAgICBicmVhazsKPiA+ICsgICAgICAgZGVmYXVs dDoKPiA+ICsgICAgICAgICAgICAgICBwZGF0YS0+bW9kZSA9IFVTQl9EUl9NT0RFX09URzsKPiA+ ICsgICAgICAgICAgICAgICAvKiBGQUxMIFRIUk9VR0ggKi8KPiA+ICsgICAgICAgY2FzZSBVU0Jf RFJfTU9ERV9PVEc6Cj4gPiArICAgICAgICAgICAgICAgZ2x1ZS0+cGh5X21vZGUgPSBQSFlfTU9E RV9VU0JfT1RHOwo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOwo+ID4gKyAgICAgICB9Cj4gPiAr Cj4gPiArICAgICAgIGdsdWUtPnBoeSA9IGRldm1fb2ZfcGh5X2dldF9ieV9pbmRleChkZXYsIG5w LCAwKTsKPiA+ICsgICAgICAgaWYgKElTX0VSUihnbHVlLT5waHkpKSB7Cj4gPiArICAgICAgICAg ICAgICAgZGV2X2VycihkZXYsICJmYWlsIHRvIGdldHRpbmcgcGh5ICVsZFxuIiwKPiA+ICsgICAg ICAgICAgICAgICAgICAgICAgIFBUUl9FUlIoZ2x1ZS0+cGh5KSk7Cj4gPiArICAgICAgICAgICAg ICAgcmV0dXJuIFBUUl9FUlIoZ2x1ZS0+cGh5KTsKPiA+ICsgICAgICAgfQo+ID4gKwo+ID4gKyAg ICAgICBnbHVlLT51c2JfcGh5ID0gdXNiX3BoeV9nZW5lcmljX3JlZ2lzdGVyKCk7Cj4gPiArICAg ICAgIGlmIChJU19FUlIoZ2x1ZS0+dXNiX3BoeSkpIHsKPiA+ICsgICAgICAgICAgICAgICBkZXZf ZXJyKGRldiwgImZhaWwgdG8gcmVnaXN0ZXJpbmcgdXNiLXBoeSAlbGRcbiIsCj4gPiArICAgICAg ICAgICAgICAgICAgICAgICBQVFJfRVJSKGdsdWUtPnVzYl9waHkpKTsKPiA+ICsgICAgICAgICAg ICAgICByZXR1cm4gUFRSX0VSUihnbHVlLT51c2JfcGh5KTsKPiA+ICsgICAgICAgfQo+ID4gKwo+ ID4gKyAgICAgICBnbHVlLT54Y2VpdiA9IGRldm1fdXNiX2dldF9waHkoZGV2LCBVU0JfUEhZX1RZ UEVfVVNCMik7Cj4gPiArICAgICAgIGlmIChJU19FUlIoZ2x1ZS0+eGNlaXYpKSB7Cj4gPiArICAg ICAgICAgICAgICAgZGV2X2VycihkZXYsICJmYWlsIHRvIGdldHRpbmcgdXNiLXBoeSAlZFxuIiwg cmV0KTsKPiA+ICsgICAgICAgICAgICAgICByZXQgPSBQVFJfRVJSKGdsdWUtPnhjZWl2KTsKPiA+ ICsgICAgICAgICAgICAgICBnb3RvIGVycl91bnJlZ2lzdGVyX3VzYl9waHk7Cj4gPiArICAgICAg IH0KPiA+ICsKPiA+ICsgICAgICAgcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgZ2x1ZSk7Cj4g PiArICAgICAgIHBtX3J1bnRpbWVfZW5hYmxlKGRldik7Cj4gPiArICAgICAgIHBtX3J1bnRpbWVf Z2V0X3N5bmMoZGV2KTsKPiA+ICsKPiA+ICsgICAgICAgcmV0ID0gbXRrX211c2JfY2xrc19lbmFi bGUoZ2x1ZSk7Cj4gPiArICAgICAgIGlmIChyZXQpCj4gPiArICAgICAgICAgICAgICAgZ290byBl cnJfZW5hYmxlX2NsazsKPiA+ICsKPiA+ICsgICAgICAgcGluZm8gPSBtdGtfZGV2X2luZm87Cj4g PiArICAgICAgIHBpbmZvLnBhcmVudCA9IGRldjsKPiA+ICsgICAgICAgcGluZm8ucmVzID0gcGRl di0+cmVzb3VyY2U7Cj4gPiArICAgICAgIHBpbmZvLm51bV9yZXMgPSBwZGV2LT5udW1fcmVzb3Vy Y2VzOwo+ID4gKyAgICAgICBwaW5mby5kYXRhID0gcGRhdGE7Cj4gPiArICAgICAgIHBpbmZvLnNp emVfZGF0YSA9IHNpemVvZigqcGRhdGEpOwo+ID4gKwo+ID4gKyAgICAgICBnbHVlLT5tdXNiX3Bk ZXYgPSBwbGF0Zm9ybV9kZXZpY2VfcmVnaXN0ZXJfZnVsbCgmcGluZm8pOwo+ID4gKyAgICAgICBp ZiAoSVNfRVJSKGdsdWUtPm11c2JfcGRldikpIHsKPiA+ICsgICAgICAgICAgICAgICByZXQgPSBQ VFJfRVJSKGdsdWUtPm11c2JfcGRldik7Cj4gPiArICAgICAgICAgICAgICAgZGV2X2VycihkZXYs ICJmYWlsZWQgdG8gcmVnaXN0ZXIgbXVzYiBkZXZpY2U6ICVkXG4iLCByZXQpOwo+ID4gKyAgICAg ICAgICAgICAgIGdvdG8gZXJyX2RldmljZV9yZWdpc3RlcjsKPiA+ICsgICAgICAgfQo+ID4gKwo+ ID4gKyAgICAgICBpZiAocGRhdGEtPm1vZGUgPT0gVVNCX0RSX01PREVfT1RHKQo+ID4gKyAgICAg ICAgICAgICAgIG10a19vdGdfc3dpdGNoX2luaXQoZ2x1ZSk7Cj4gPiArCj4gPiArICAgICAgIHJl dHVybiAwOwo+ID4gKwo+ID4gK2Vycl9kZXZpY2VfcmVnaXN0ZXI6Cj4gPiArICAgICAgIG10a19t dXNiX2Nsa3NfZGlzYWJsZShnbHVlKTsKPiA+ICtlcnJfZW5hYmxlX2NsazoKPiA+ICsgICAgICAg cG1fcnVudGltZV9wdXRfc3luYyhkZXYpOwo+ID4gKyAgICAgICBwbV9ydW50aW1lX2Rpc2FibGUo ZGV2KTsKPiA+ICtlcnJfdW5yZWdpc3Rlcl91c2JfcGh5Ogo+ID4gKyAgICAgICB1c2JfcGh5X2dl bmVyaWNfdW5yZWdpc3RlcihnbHVlLT51c2JfcGh5KTsKPiA+ICsgICAgICAgcmV0dXJuIHJldDsK PiA+ICt9Cj4gPiArCj4gPiArc3RhdGljIGludCBtdGtfbXVzYl9yZW1vdmUoc3RydWN0IHBsYXRm b3JtX2RldmljZSAqcGRldikKPiA+ICt7Cj4gPiArICAgICAgIHN0cnVjdCBtdGtfZ2x1ZSAqZ2x1 ZSA9IHBsYXRmb3JtX2dldF9kcnZkYXRhKHBkZXYpOwo+ID4gKyAgICAgICBzdHJ1Y3QgcGxhdGZv cm1fZGV2aWNlICp1c2JfcGh5ID0gZ2x1ZS0+dXNiX3BoeTsKPiA+ICsKPiA+ICsgICAgICAgcGxh dGZvcm1fZGV2aWNlX3VucmVnaXN0ZXIoZ2x1ZS0+bXVzYl9wZGV2KTsKPiA+ICsgICAgICAgdXNi X3BoeV9nZW5lcmljX3VucmVnaXN0ZXIodXNiX3BoeSk7Cj4gPiArCj4gPiArICAgICAgIHJldHVy biAwOwo+ID4gK30KPiA+ICsKPiA+ICsjaWZkZWYgQ09ORklHX09GCj4gPiArc3RhdGljIGNvbnN0 IHN0cnVjdCBvZl9kZXZpY2VfaWQgbXRrX211c2JfbWF0Y2hbXSA9IHsKPiA+ICsgICAgICAgey5j b21wYXRpYmxlID0gIm1lZGlhdGVrLG10ay1tdXNiIix9LAo+ID4gKyAgICAgICB7fSwKPiA+ICt9 Owo+ID4gK01PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIG10a19tdXNiX21hdGNoKTsKPiA+ICsjZW5k aWYKPiA+ICsKPiA+ICtzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBtdGtfbXVzYl9kcml2 ZXIgPSB7Cj4gPiArICAgICAgIC5wcm9iZSA9IG10a19tdXNiX3Byb2JlLAo+ID4gKyAgICAgICAu cmVtb3ZlID0gbXRrX211c2JfcmVtb3ZlLAo+ID4gKyAgICAgICAuZHJpdmVyID0gewo+ID4gKyAg ICAgICAgICAgICAgICAgIC5uYW1lID0gIm11c2ItbXRrIiwKPiA+ICsgICAgICAgICAgICAgICAg ICAub2ZfbWF0Y2hfdGFibGUgPSBvZl9tYXRjaF9wdHIobXRrX211c2JfbWF0Y2gpLAo+ID4gKyAg ICAgICB9LAo+ID4gK307Cj4gPiArCj4gPiArbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihtdGtfbXVz Yl9kcml2ZXIpOwo+ID4gKwo+ID4gK01PRFVMRV9ERVNDUklQVElPTigiTWVkaWFUZWsgTVVTQiBH bHVlIExheWVyIik7Cj4gPiArTU9EVUxFX0FVVEhPUigiTWluIEd1byA8bWluLmd1b0BtZWRpYXRl ay5jb20+Iik7Cj4gPiArTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwo+ID4gLS0KPiA+IDEuOS4x Cj4gPgo+ID4KPiA+IF9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fCj4gPiBsaW51eC1hcm0ta2VybmVsIG1haWxpbmcgbGlzdAo+ID4gbGludXgtYXJtLWtlcm5l bEBsaXN0cy5pbmZyYWRlYWQub3JnCj4gPiBodHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWls bWFuL2xpc3RpbmZvL2xpbnV4LWFybS1rZXJuZWwK From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 36A9EC43381 for ; Mon, 1 Apr 2019 05:35:56 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 02F312086C for ; Mon, 1 Apr 2019 05:35:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="WloDXs0V" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 02F312086C Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Date:To:From:Subject:Message-ID:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=CGiDC6h7yka0v7OzcmIbBQO9GXFdBRpvvHR2DqKxcx8=; b=WloDXs0VlNWHT5 Y50+2dc3jIEln2wV/BL6QmVKQLsaM6aRg8dzSbwobpDLYta2dcjfEQOPMXzTtgN7QYz7i4GdkfkeM QDX+QHjlqqeCtqHvKPhbIkj/4UE0MH6QdnsWJ+rSOcJ5Gd6DHQwJP3ZHFYISOvQFnypOXFmDF5brc 3ZyNl1UbbkbuqdSQBivv9FfpaXcsPfVZIV+uxLWkN2ETwoEfW9im6x3L/3/kydQnOP1QnbGvdmMFZ wM/pCEhCY2UOu447C/V7rHrfQk9GalYeMLodK0mrxFcAlTxJSjLCazOjDVBV4QWp7HJgurzT2kVFp vMJNjOpsv3bOHtG90JJA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hApbq-0006V6-86; Mon, 01 Apr 2019 05:35:50 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hApbi-0006U8-PR; Mon, 01 Apr 2019 05:35:48 +0000 X-UUID: 698fb1b7f8a44f45a4a9c7640765db3e-20190331 X-UUID: 698fb1b7f8a44f45a4a9c7640765db3e-20190331 Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 224823792; Sun, 31 Mar 2019 21:35:30 -0800 Received: from MTKMBS31DR.mediatek.inc (172.27.6.102) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sun, 31 Mar 2019 22:35:28 -0700 Received: from MTKCAS36.mediatek.inc (172.27.4.186) by MTKMBS31DR.mediatek.inc (172.27.6.102) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 1 Apr 2019 13:35:24 +0800 Received: from [10.17.3.153] (172.27.4.253) by MTKCAS36.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 1 Apr 2019 13:35:24 +0800 Message-ID: <1554096924.19123.3.camel@mhfsdcap03> Subject: Re: [PATCH v5 6/6] usb: musb: Add support for MediaTek musb controller From: Min Guo To: Fabien Parent Date: Mon, 1 Apr 2019 13:35:24 +0800 In-Reply-To: References: <1550561795-31132-1-git-send-email-min.guo@mediatek.com> <1550561795-31132-7-git-send-email-min.guo@mediatek.com> X-Mailer: Evolution 3.2.3-0ubuntu6 MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190331_223544_496570_ED624352 X-CRM114-Status: GOOD ( 27.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , devicetree@vger.kernel.org, Yonglong Wu , tony@atomide.com, Greg Kroah-Hartman , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, chunfeng.yun@mediatek.com, hdegoede@redhat.com, Rob Herring , Alan Stern , Matthias Brugger , linux-mediatek@lists.infradead.org, Bin Liu , linux-arm-kernel@lists.infradead.org Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+infradead-linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hi Fabien Parent, On Sat, 2019-03-30 at 09:52 +0100, Fabien Parent wrote: > Hi Min Guo, > > On Tue, Feb 19, 2019 at 8:39 AM wrote: > > > > From: Min Guo > > > > This adds support for MediaTek musb controller in > > host, peripheral and otg mode. > > There are some quirk of MediaTek musb controller, such as: > > -W1C interrupt status registers > > -Private data toggle registers > > -No dedicated DMA interrupt line > > > > Signed-off-by: Min Guo > > Signed-off-by: Yonglong Wu > > --- > > changes in v5: > > 1. Replace musb_readb() with musb_clearb() to clear common/tx/rx pending interrupts > > 2. Make musb_clearb/w() return the value of musb_readb/w() > > 3. Add driver to get child nodes of usb connector and extcon device > > > > changes in v4: > > 1. no changes > > > > changes in v3: > > suggested by Bin: > > 1. Remove 'u8/u16 data' parameter in clearb/w() hooks > > 2. Replace musb_readb/w() with musb_clearb/w() to clear interrupts status > > > > changes in v2: > > suggested by Bin: > > 1. Add summarize of MediaTek musb controller differences in the commit log > > 2. Add "|| COMPILE_TEST" in Kconfig > > 3. Move MediaTek's private toggle registers from musb_regs.h to mediatek.c > > 4. Replace musb_readl() with musb_readw() to read 16bit toggle register > > --- > > drivers/usb/musb/Kconfig | 8 +- > > drivers/usb/musb/Makefile | 1 + > > drivers/usb/musb/mediatek.c | 629 ++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 637 insertions(+), 1 deletion(-) > > create mode 100644 drivers/usb/musb/mediatek.c > > > > diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig > > index ad08895..b72b7c1 100644 > > --- a/drivers/usb/musb/Kconfig > > +++ b/drivers/usb/musb/Kconfig > > @@ -115,6 +115,12 @@ config USB_MUSB_JZ4740 > > depends on USB_MUSB_GADGET > > depends on USB_OTG_BLACKLIST_HUB > > > > +config USB_MUSB_MEDIATEK > > + tristate "MediaTek platforms" > > + depends on ARCH_MEDIATEK || COMPILE_TEST > > + depends on NOP_USB_XCEIV > > + depends on GENERIC_PHY > > + > > config USB_MUSB_AM335X_CHILD > > tristate > > > > @@ -141,7 +147,7 @@ config USB_UX500_DMA > > > > config USB_INVENTRA_DMA > > bool 'Inventra' > > - depends on USB_MUSB_OMAP2PLUS > > + depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK > > help > > Enable DMA transfers using Mentor's engine. > > > > diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile > > index 3a88c79..63d82d0 100644 > > --- a/drivers/usb/musb/Makefile > > +++ b/drivers/usb/musb/Makefile > > @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o > > obj-$(CONFIG_USB_MUSB_UX500) += ux500.o > > obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o > > obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o > > +obj-$(CONFIG_USB_MUSB_MEDIATEK) += mediatek.o > > > > > > obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o > > diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c > > new file mode 100644 > > index 0000000..946b453 > > --- /dev/null > > +++ b/drivers/usb/musb/mediatek.c > > @@ -0,0 +1,629 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2018 MediaTek Inc. > > + * > > + * Author: > > + * Min Guo > > + * Yonglong Wu > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include "musb_core.h" > > +#include "musb_dma.h" > > + > > +#define USB_L1INTS 0x00a0 > > +#define USB_L1INTM 0x00a4 > > +#define MTK_MUSB_TXFUNCADDR 0x0480 > > + > > +/* MediaTek controller toggle enable and status reg */ > > +#define MUSB_RXTOG 0x80 > > +#define MUSB_RXTOGEN 0x82 > > +#define MUSB_TXTOG 0x84 > > +#define MUSB_TXTOGEN 0x86 > > + > > +#define TX_INT_STATUS BIT(0) > > +#define RX_INT_STATUS BIT(1) > > +#define USBCOM_INT_STATUS BIT(2) > > +#define DMA_INT_STATUS BIT(3) > > + > > +#define DMA_INTR_STATUS_MSK GENMASK(7, 0) > > +#define DMA_INTR_UNMASK_SET_MSK GENMASK(31, 24) > > + > > +enum mtk_vbus_id_state { > > + MTK_ID_FLOAT = 1, > > + MTK_ID_GROUND, > > + MTK_VBUS_OFF, > > + MTK_VBUS_VALID, > > +}; > > + > > +struct mtk_glue { > > + struct device *dev; > > + struct musb *musb; > > + struct platform_device *musb_pdev; > > + struct platform_device *usb_phy; > > + struct phy *phy; > > + struct usb_phy *xceiv; > > + enum phy_mode phy_mode; > > + struct clk *main; > > + struct clk *mcu; > > + struct clk *univpll; > > + struct regulator *vbus; > > + struct extcon_dev *edev; > > + struct notifier_block vbus_nb; > > + struct notifier_block id_nb; > > +}; > > + > > +static int mtk_musb_clks_get(struct mtk_glue *glue) > > +{ > > + struct device *dev = glue->dev; > > + > > + glue->main = devm_clk_get(dev, "main"); > > + if (IS_ERR(glue->main)) { > > + dev_err(dev, "fail to get main clock\n"); > > + return PTR_ERR(glue->main); > > + } > > + > > + glue->mcu = devm_clk_get(dev, "mcu"); > > + if (IS_ERR(glue->mcu)) { > > + dev_err(dev, "fail to get mcu clock\n"); > > + return PTR_ERR(glue->mcu); > > + } > > + > > + glue->univpll = devm_clk_get(dev, "univpll"); > > + if (IS_ERR(glue->univpll)) { > > + dev_err(dev, "fail to get univpll clock\n"); > > + return PTR_ERR(glue->univpll); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_clks_enable(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + ret = clk_prepare_enable(glue->main); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable main clock\n"); > > + goto err_main_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->mcu); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable mcu clock\n"); > > + goto err_mcu_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->univpll); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable univpll clock\n"); > > + goto err_univpll_clk; > > + } > > + > > + return 0; > > + > > +err_univpll_clk: > > + clk_disable_unprepare(glue->mcu); > > +err_mcu_clk: > > + clk_disable_unprepare(glue->main); > > +err_main_clk: > > + return ret; > > +} > > + > > +static void mtk_musb_clks_disable(struct mtk_glue *glue) > > +{ > > + clk_disable_unprepare(glue->univpll); > > + clk_disable_unprepare(glue->mcu); > > + clk_disable_unprepare(glue->main); > > +} > > + > > +static void mtk_musb_set_vbus(struct musb *musb, int is_on) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + /* vbus is optional */ > > + if (!glue->vbus) > > + return; > > + > > + dev_dbg(musb->controller, "%s, is_on=%d\r\n", __func__, is_on); > > + if (is_on) { > > + ret = regulator_enable(glue->vbus); > > + if (ret) { > > + dev_err(glue->dev, "fail to enable vbus regulator\n"); > > + return; > > + } > > + } else { > > + regulator_disable(glue->vbus); > > + } > > +} > > + > > +/* > > + * switch to host: -> MTK_VBUS_OFF --> MTK_ID_GROUND > > + * switch to device: -> MTK_ID_FLOAT --> MTK_VBUS_VALID > > + */ > > +static void mtk_musb_set_mailbox(struct mtk_glue *glue, > > + enum mtk_vbus_id_state status) > > +{ > > + struct musb *musb = glue->musb; > > + u8 devctl = 0; > > + > > + dev_dbg(glue->dev, "mailbox state(%d)\n", status); > > + switch (status) { > > + case MTK_ID_GROUND: > > + phy_power_on(glue->phy); > > + devctl = readb(musb->mregs + MUSB_DEVCTL); > > + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; > > + mtk_musb_set_vbus(musb, 1); > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + devctl |= MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + MUSB_HST_MODE(musb); > > + break; > > + /* > > + * MTK_ID_FLOAT process is the same as MTK_VBUS_VALID > > + * except that turn off VBUS > > + */ > > + case MTK_ID_FLOAT: > > + mtk_musb_set_vbus(musb, 0); > > + /* fall through */ > > + case MTK_VBUS_OFF: > > + musb->xceiv->otg->state = OTG_STATE_B_IDLE; > > + devctl &= ~MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + phy_power_off(glue->phy); > > + break; > > + case MTK_VBUS_VALID: > > + phy_power_on(glue->phy); > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + MUSB_DEV_MODE(musb); > > + break; > > + default: > > + dev_err(glue->dev, "invalid state\n"); > > + } > > +} > > + > > +static int mtk_musb_id_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, id_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + else > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static int mtk_musb_vbus_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, vbus_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > + else > > + mtk_musb_set_mailbox(glue, MTK_VBUS_OFF); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static void mtk_otg_switch_init(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + /* extcon is optional */ > > + if (!glue->edev) > > + return; > > + > > + glue->vbus_nb.notifier_call = mtk_musb_vbus_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, EXTCON_USB, > > + &glue->vbus_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB\n"); > > + > > + glue->id_nb.notifier_call = mtk_musb_id_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, > > + EXTCON_USB_HOST, &glue->id_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB-HOST\n"); > > + > > + dev_dbg(glue->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", > > + extcon_get_state(glue->edev, EXTCON_USB), > > + extcon_get_state(glue->edev, EXTCON_USB_HOST)); > > + > > + /* default as host, switch to device mode if needed */ > > + if (extcon_get_state(glue->edev, EXTCON_USB_HOST) == false) > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + if (extcon_get_state(glue->edev, EXTCON_USB) == true) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > +} > > + > > +static irqreturn_t generic_interrupt(int irq, void *__hci) > > +{ > > + unsigned long flags; > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = __hci; > > + > > + spin_lock_irqsave(&musb->lock, flags); > > + musb->int_usb = musb_clearb(musb->mregs, MUSB_INTRUSB); > > + musb->int_rx = musb_clearw(musb->mregs, MUSB_INTRRX); > > + musb->int_tx = musb_clearw(musb->mregs, MUSB_INTRTX); > > + > > + if (musb->int_usb || musb->int_tx || musb->int_rx) > > + retval = musb_interrupt(musb); > > + > > + spin_unlock_irqrestore(&musb->lock, flags); > > + > > + return retval; > > +} > > + > > +static irqreturn_t mtk_musb_interrupt(int irq, void *dev_id) > > +{ > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = (struct musb *)dev_id; > > + u32 l1_ints; > > + > > + l1_ints = musb_readl(musb->mregs, USB_L1INTS) & > > + musb_readl(musb->mregs, USB_L1INTM); > > + > > + if (l1_ints & (TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS)) > > + retval = generic_interrupt(irq, musb); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + if (l1_ints & DMA_INT_STATUS) > > + retval = dma_controller_irq(irq, musb->dma_controller); > > +#endif > > + return retval; > > +} > > + > > +static u32 mtk_musb_busctl_offset(u8 epnum, u16 offset) > > +{ > > + return MTK_MUSB_TXFUNCADDR + offset + 8 * epnum; > > +} > > + > > +static u8 mtk_musb_clearb(void __iomem *addr, unsigned int offset) > > +{ > > + u8 data; > > + > > + /* W1C */ > > + data = musb_readb(addr, offset); > > + musb_writeb(addr, offset, data); > > + return data; > > +} > > + > > +static u16 mtk_musb_clearw(void __iomem *addr, unsigned int offset) > > +{ > > + u16 data; > > + > > + /* W1C */ > > + data = musb_readw(addr, offset); > > + musb_writew(addr, offset, data); > > + return data; > > +} > > + > > +static int mtk_musb_init(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + glue->musb = musb; > > + musb->phy = glue->phy; > > + musb->xceiv = glue->xceiv; > > + musb->is_host = false; > > + musb->isr = mtk_musb_interrupt; > > + ret = phy_init(glue->phy); > > + if (ret) > > + return ret; > > + > > + ret = phy_power_on(glue->phy); > > + if (ret) { > > + phy_exit(glue->phy); > > + return ret; > > + } > > + > > + phy_set_mode(glue->phy, glue->phy_mode); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + musb_writel(musb->mregs, MUSB_HSDMA_INTR, > > + DMA_INTR_STATUS_MSK | DMA_INTR_UNMASK_SET_MSK); > > +#endif > > + musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | > > + USBCOM_INT_STATUS | DMA_INT_STATUS); > > + return 0; > > +} > > + > > +static u16 mtk_musb_get_toggle(struct musb_qh *qh, int is_out) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + if (is_out) > > + toggle = musb_readw(musb->mregs, MUSB_TXTOG); > > + else > > + toggle = musb_readw(musb->mregs, MUSB_RXTOG); > > + > > + return toggle & (1 << epnum); > > +} > > + > > +static u16 mtk_musb_set_toggle(struct musb_qh *qh, int is_out, struct urb *urb) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + toggle = usb_gettoggle(urb->dev, qh->epnum, is_out); > > + > > + if (is_out) { > > + musb_writew(musb->mregs, MUSB_TXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_TXTOG, (toggle << epnum)); > > + } else { > > + musb_writew(musb->mregs, MUSB_RXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_RXTOG, (toggle << epnum)); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_set_mode(struct musb *musb, u8 mode) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + enum phy_mode new_mode; > > + > > + switch (mode) { > > + case MUSB_HOST: > > + new_mode = PHY_MODE_USB_HOST; > > + mtk_musb_set_vbus(musb, 1); > > + break; > > + case MUSB_PERIPHERAL: > > + new_mode = PHY_MODE_USB_DEVICE; > > + break; > > + case MUSB_OTG: > > + new_mode = PHY_MODE_USB_HOST; > > + break; > > + default: > > + dev_err(musb->controller->parent, > > + "Error requested mode not supported by this kernel\n"); > > + return -EINVAL; > > + } > > + if (glue->phy_mode == new_mode) > > + return 0; > > + > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + return 0; > > +} > > + > > +static int mtk_musb_exit(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + > > + phy_power_off(glue->phy); > > + phy_exit(glue->phy); > > + mtk_musb_clks_disable(glue); > > + > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > + return 0; > > +} > > + > > +static const struct musb_platform_ops mtk_musb_ops = { > > + .quirks = MUSB_DMA_INVENTRA, > > + .init = mtk_musb_init, > > + .get_toggle = mtk_musb_get_toggle, > > + .set_toggle = mtk_musb_set_toggle, > > + .exit = mtk_musb_exit, > > +#ifdef CONFIG_USB_INVENTRA_DMA > > + .dma_init = musbhs_dma_controller_create_noirq, > > + .dma_exit = musbhs_dma_controller_destroy, > > +#endif > > + .clearb = mtk_musb_clearb, > > + .clearw = mtk_musb_clearw, > > + .busctl_offset = mtk_musb_busctl_offset, > > + .set_mode = mtk_musb_set_mode, > > + .set_vbus = mtk_musb_set_vbus, > > +}; > > + > > +#define MTK_MUSB_MAX_EP_NUM 8 > > +#define MTK_MUSB_RAM_BITS 11 > > + > > +static struct musb_fifo_cfg mtk_musb_mode_cfg[] = { > > + { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 1024, }, > > + { .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 1024, }, > > + { .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 64, }, > > +}; > > + > > +static const struct musb_hdrc_config mtk_musb_hdrc_config = { > > + .fifo_cfg = mtk_musb_mode_cfg, > > + .fifo_cfg_size = ARRAY_SIZE(mtk_musb_mode_cfg), > > + .multipoint = true, > > + .dyn_fifo = true, > > + .num_eps = MTK_MUSB_MAX_EP_NUM, > > + .ram_bits = MTK_MUSB_RAM_BITS, > > +}; > > + > > +static const struct platform_device_info mtk_dev_info = { > > + .name = "musb-hdrc", > > + .id = PLATFORM_DEVID_AUTO, > > + .dma_mask = DMA_BIT_MASK(32), > > +}; > > + > > +static int mtk_musb_probe(struct platform_device *pdev) > > +{ > > + struct musb_hdrc_platform_data *pdata; > > + struct mtk_glue *glue; > > + struct platform_device_info pinfo; > > + struct device *dev = &pdev->dev; > > + struct device_node *np = dev->of_node; > > + struct device_node *child, *extcon_node; > > + int ret = -ENOMEM; > > + > > + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); > > + if (!glue) > > + return -ENOMEM; > > + > > + glue->dev = dev; > > + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); > > + if (!pdata) > > + return -ENOMEM; > > + > > + ret = mtk_musb_clks_get(glue); > > + if (ret) > > + return ret; > > + > > + pdata->config = &mtk_musb_hdrc_config; > > + pdata->platform_ops = &mtk_musb_ops; > > + > > + glue->vbus = devm_regulator_get(dev, "vbus"); > > + if (IS_ERR(glue->vbus)) { > > + dev_err(dev, "fail to get vbus\n"); > > + return PTR_ERR(glue->vbus); > > + } > > + > > + child = of_get_child_by_name(np, "connector"); > > + if (!child) { > > + dev_err(dev, "failed to find usb connector node\n"); > > + return ERR_PTR(-ENODEV); > > The 'probe' function is returning an 'int' and not a pointer. This > line should trigger a warning. OK, thanks. > > + } > > + > > + extcon_node = of_parse_phandle(child, "extcon", 0); > > + if (!extcon_node) { > > + dev_err(dev, "failed to get extcon phandle"); > > + return ERR_PTR(-ENODEV); > > Same here OK, thanks. > > + } > > + > > + glue->edev = extcon_find_edev_by_node(extcon_node); > > + if (IS_ERR(glue->edev)) { > > + dev_err(dev, "fail to get extcon\n"); > > + return PTR_ERR(glue->edev); > > + } > > + > > + pdata->mode = usb_get_dr_mode(dev); > > + switch (pdata->mode) { > > + case USB_DR_MODE_HOST: > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + break; > > + case USB_DR_MODE_PERIPHERAL: > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + break; > > + default: > > + pdata->mode = USB_DR_MODE_OTG; > > + /* FALL THROUGH */ > > + case USB_DR_MODE_OTG: > > + glue->phy_mode = PHY_MODE_USB_OTG; > > + break; > > + } > > + > > + glue->phy = devm_of_phy_get_by_index(dev, np, 0); > > + if (IS_ERR(glue->phy)) { > > + dev_err(dev, "fail to getting phy %ld\n", > > + PTR_ERR(glue->phy)); > > + return PTR_ERR(glue->phy); > > + } > > + > > + glue->usb_phy = usb_phy_generic_register(); > > + if (IS_ERR(glue->usb_phy)) { > > + dev_err(dev, "fail to registering usb-phy %ld\n", > > + PTR_ERR(glue->usb_phy)); > > + return PTR_ERR(glue->usb_phy); > > + } > > + > > + glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); > > + if (IS_ERR(glue->xceiv)) { > > + dev_err(dev, "fail to getting usb-phy %d\n", ret); > > + ret = PTR_ERR(glue->xceiv); > > + goto err_unregister_usb_phy; > > + } > > + > > + platform_set_drvdata(pdev, glue); > > + pm_runtime_enable(dev); > > + pm_runtime_get_sync(dev); > > + > > + ret = mtk_musb_clks_enable(glue); > > + if (ret) > > + goto err_enable_clk; > > + > > + pinfo = mtk_dev_info; > > + pinfo.parent = dev; > > + pinfo.res = pdev->resource; > > + pinfo.num_res = pdev->num_resources; > > + pinfo.data = pdata; > > + pinfo.size_data = sizeof(*pdata); > > + > > + glue->musb_pdev = platform_device_register_full(&pinfo); > > + if (IS_ERR(glue->musb_pdev)) { > > + ret = PTR_ERR(glue->musb_pdev); > > + dev_err(dev, "failed to register musb device: %d\n", ret); > > + goto err_device_register; > > + } > > + > > + if (pdata->mode == USB_DR_MODE_OTG) > > + mtk_otg_switch_init(glue); > > + > > + return 0; > > + > > +err_device_register: > > + mtk_musb_clks_disable(glue); > > +err_enable_clk: > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > +err_unregister_usb_phy: > > + usb_phy_generic_unregister(glue->usb_phy); > > + return ret; > > +} > > + > > +static int mtk_musb_remove(struct platform_device *pdev) > > +{ > > + struct mtk_glue *glue = platform_get_drvdata(pdev); > > + struct platform_device *usb_phy = glue->usb_phy; > > + > > + platform_device_unregister(glue->musb_pdev); > > + usb_phy_generic_unregister(usb_phy); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_OF > > +static const struct of_device_id mtk_musb_match[] = { > > + {.compatible = "mediatek,mtk-musb",}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, mtk_musb_match); > > +#endif > > + > > +static struct platform_driver mtk_musb_driver = { > > + .probe = mtk_musb_probe, > > + .remove = mtk_musb_remove, > > + .driver = { > > + .name = "musb-mtk", > > + .of_match_table = of_match_ptr(mtk_musb_match), > > + }, > > +}; > > + > > +module_platform_driver(mtk_musb_driver); > > + > > +MODULE_DESCRIPTION("MediaTek MUSB Glue Layer"); > > +MODULE_AUTHOR("Min Guo "); > > +MODULE_LICENSE("GPL v2"); > > -- > > 1.9.1 > > > > > > _______________________________________________ > > linux-arm-kernel mailing list > > linux-arm-kernel@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,UNPARSEABLE_RELAY, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A17FFC43381 for ; Mon, 1 Apr 2019 05:35:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5B4332086C for ; Mon, 1 Apr 2019 05:35:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727056AbfDAFfm (ORCPT ); Mon, 1 Apr 2019 01:35:42 -0400 Received: from Mailgw01.mediatek.com ([1.203.163.78]:11639 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1725771AbfDAFfl (ORCPT ); Mon, 1 Apr 2019 01:35:41 -0400 X-UUID: f52c271d2b504bd2a3dbd222db58c10a-20190401 X-UUID: f52c271d2b504bd2a3dbd222db58c10a-20190401 Received: from mtkcas34.mediatek.inc [(172.27.4.253)] by mailgw01.mediatek.com (envelope-from ) (mailgw01.mediatek.com ESMTP with TLS) with ESMTP id 1776606883; Mon, 01 Apr 2019 13:35:27 +0800 Received: from MTKCAS36.mediatek.inc (172.27.4.186) by MTKMBS31DR.mediatek.inc (172.27.6.102) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 1 Apr 2019 13:35:24 +0800 Received: from [10.17.3.153] (172.27.4.253) by MTKCAS36.mediatek.inc (172.27.4.170) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 1 Apr 2019 13:35:24 +0800 Message-ID: <1554096924.19123.3.camel@mhfsdcap03> Subject: Re: [PATCH v5 6/6] usb: musb: Add support for MediaTek musb controller From: Min Guo To: Fabien Parent CC: Bin Liu , Rob Herring , Mark Rutland , , Yonglong Wu , , , "Greg Kroah-Hartman" , , , Matthias Brugger , Alan Stern , , , Date: Mon, 1 Apr 2019 13:35:24 +0800 In-Reply-To: References: <1550561795-31132-1-git-send-email-min.guo@mediatek.com> <1550561795-31132-7-git-send-email-min.guo@mediatek.com> Content-Type: text/plain; charset="UTF-8" X-Mailer: Evolution 3.2.3-0ubuntu6 Content-Transfer-Encoding: 7bit MIME-Version: 1.0 X-MTK: N Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Fabien Parent, On Sat, 2019-03-30 at 09:52 +0100, Fabien Parent wrote: > Hi Min Guo, > > On Tue, Feb 19, 2019 at 8:39 AM wrote: > > > > From: Min Guo > > > > This adds support for MediaTek musb controller in > > host, peripheral and otg mode. > > There are some quirk of MediaTek musb controller, such as: > > -W1C interrupt status registers > > -Private data toggle registers > > -No dedicated DMA interrupt line > > > > Signed-off-by: Min Guo > > Signed-off-by: Yonglong Wu > > --- > > changes in v5: > > 1. Replace musb_readb() with musb_clearb() to clear common/tx/rx pending interrupts > > 2. Make musb_clearb/w() return the value of musb_readb/w() > > 3. Add driver to get child nodes of usb connector and extcon device > > > > changes in v4: > > 1. no changes > > > > changes in v3: > > suggested by Bin: > > 1. Remove 'u8/u16 data' parameter in clearb/w() hooks > > 2. Replace musb_readb/w() with musb_clearb/w() to clear interrupts status > > > > changes in v2: > > suggested by Bin: > > 1. Add summarize of MediaTek musb controller differences in the commit log > > 2. Add "|| COMPILE_TEST" in Kconfig > > 3. Move MediaTek's private toggle registers from musb_regs.h to mediatek.c > > 4. Replace musb_readl() with musb_readw() to read 16bit toggle register > > --- > > drivers/usb/musb/Kconfig | 8 +- > > drivers/usb/musb/Makefile | 1 + > > drivers/usb/musb/mediatek.c | 629 ++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 637 insertions(+), 1 deletion(-) > > create mode 100644 drivers/usb/musb/mediatek.c > > > > diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig > > index ad08895..b72b7c1 100644 > > --- a/drivers/usb/musb/Kconfig > > +++ b/drivers/usb/musb/Kconfig > > @@ -115,6 +115,12 @@ config USB_MUSB_JZ4740 > > depends on USB_MUSB_GADGET > > depends on USB_OTG_BLACKLIST_HUB > > > > +config USB_MUSB_MEDIATEK > > + tristate "MediaTek platforms" > > + depends on ARCH_MEDIATEK || COMPILE_TEST > > + depends on NOP_USB_XCEIV > > + depends on GENERIC_PHY > > + > > config USB_MUSB_AM335X_CHILD > > tristate > > > > @@ -141,7 +147,7 @@ config USB_UX500_DMA > > > > config USB_INVENTRA_DMA > > bool 'Inventra' > > - depends on USB_MUSB_OMAP2PLUS > > + depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK > > help > > Enable DMA transfers using Mentor's engine. > > > > diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile > > index 3a88c79..63d82d0 100644 > > --- a/drivers/usb/musb/Makefile > > +++ b/drivers/usb/musb/Makefile > > @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o > > obj-$(CONFIG_USB_MUSB_UX500) += ux500.o > > obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o > > obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o > > +obj-$(CONFIG_USB_MUSB_MEDIATEK) += mediatek.o > > > > > > obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o > > diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c > > new file mode 100644 > > index 0000000..946b453 > > --- /dev/null > > +++ b/drivers/usb/musb/mediatek.c > > @@ -0,0 +1,629 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2018 MediaTek Inc. > > + * > > + * Author: > > + * Min Guo > > + * Yonglong Wu > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include "musb_core.h" > > +#include "musb_dma.h" > > + > > +#define USB_L1INTS 0x00a0 > > +#define USB_L1INTM 0x00a4 > > +#define MTK_MUSB_TXFUNCADDR 0x0480 > > + > > +/* MediaTek controller toggle enable and status reg */ > > +#define MUSB_RXTOG 0x80 > > +#define MUSB_RXTOGEN 0x82 > > +#define MUSB_TXTOG 0x84 > > +#define MUSB_TXTOGEN 0x86 > > + > > +#define TX_INT_STATUS BIT(0) > > +#define RX_INT_STATUS BIT(1) > > +#define USBCOM_INT_STATUS BIT(2) > > +#define DMA_INT_STATUS BIT(3) > > + > > +#define DMA_INTR_STATUS_MSK GENMASK(7, 0) > > +#define DMA_INTR_UNMASK_SET_MSK GENMASK(31, 24) > > + > > +enum mtk_vbus_id_state { > > + MTK_ID_FLOAT = 1, > > + MTK_ID_GROUND, > > + MTK_VBUS_OFF, > > + MTK_VBUS_VALID, > > +}; > > + > > +struct mtk_glue { > > + struct device *dev; > > + struct musb *musb; > > + struct platform_device *musb_pdev; > > + struct platform_device *usb_phy; > > + struct phy *phy; > > + struct usb_phy *xceiv; > > + enum phy_mode phy_mode; > > + struct clk *main; > > + struct clk *mcu; > > + struct clk *univpll; > > + struct regulator *vbus; > > + struct extcon_dev *edev; > > + struct notifier_block vbus_nb; > > + struct notifier_block id_nb; > > +}; > > + > > +static int mtk_musb_clks_get(struct mtk_glue *glue) > > +{ > > + struct device *dev = glue->dev; > > + > > + glue->main = devm_clk_get(dev, "main"); > > + if (IS_ERR(glue->main)) { > > + dev_err(dev, "fail to get main clock\n"); > > + return PTR_ERR(glue->main); > > + } > > + > > + glue->mcu = devm_clk_get(dev, "mcu"); > > + if (IS_ERR(glue->mcu)) { > > + dev_err(dev, "fail to get mcu clock\n"); > > + return PTR_ERR(glue->mcu); > > + } > > + > > + glue->univpll = devm_clk_get(dev, "univpll"); > > + if (IS_ERR(glue->univpll)) { > > + dev_err(dev, "fail to get univpll clock\n"); > > + return PTR_ERR(glue->univpll); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_clks_enable(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + ret = clk_prepare_enable(glue->main); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable main clock\n"); > > + goto err_main_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->mcu); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable mcu clock\n"); > > + goto err_mcu_clk; > > + } > > + > > + ret = clk_prepare_enable(glue->univpll); > > + if (ret) { > > + dev_err(glue->dev, "failed to enable univpll clock\n"); > > + goto err_univpll_clk; > > + } > > + > > + return 0; > > + > > +err_univpll_clk: > > + clk_disable_unprepare(glue->mcu); > > +err_mcu_clk: > > + clk_disable_unprepare(glue->main); > > +err_main_clk: > > + return ret; > > +} > > + > > +static void mtk_musb_clks_disable(struct mtk_glue *glue) > > +{ > > + clk_disable_unprepare(glue->univpll); > > + clk_disable_unprepare(glue->mcu); > > + clk_disable_unprepare(glue->main); > > +} > > + > > +static void mtk_musb_set_vbus(struct musb *musb, int is_on) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + /* vbus is optional */ > > + if (!glue->vbus) > > + return; > > + > > + dev_dbg(musb->controller, "%s, is_on=%d\r\n", __func__, is_on); > > + if (is_on) { > > + ret = regulator_enable(glue->vbus); > > + if (ret) { > > + dev_err(glue->dev, "fail to enable vbus regulator\n"); > > + return; > > + } > > + } else { > > + regulator_disable(glue->vbus); > > + } > > +} > > + > > +/* > > + * switch to host: -> MTK_VBUS_OFF --> MTK_ID_GROUND > > + * switch to device: -> MTK_ID_FLOAT --> MTK_VBUS_VALID > > + */ > > +static void mtk_musb_set_mailbox(struct mtk_glue *glue, > > + enum mtk_vbus_id_state status) > > +{ > > + struct musb *musb = glue->musb; > > + u8 devctl = 0; > > + > > + dev_dbg(glue->dev, "mailbox state(%d)\n", status); > > + switch (status) { > > + case MTK_ID_GROUND: > > + phy_power_on(glue->phy); > > + devctl = readb(musb->mregs + MUSB_DEVCTL); > > + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; > > + mtk_musb_set_vbus(musb, 1); > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + devctl |= MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + MUSB_HST_MODE(musb); > > + break; > > + /* > > + * MTK_ID_FLOAT process is the same as MTK_VBUS_VALID > > + * except that turn off VBUS > > + */ > > + case MTK_ID_FLOAT: > > + mtk_musb_set_vbus(musb, 0); > > + /* fall through */ > > + case MTK_VBUS_OFF: > > + musb->xceiv->otg->state = OTG_STATE_B_IDLE; > > + devctl &= ~MUSB_DEVCTL_SESSION; > > + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); > > + phy_power_off(glue->phy); > > + break; > > + case MTK_VBUS_VALID: > > + phy_power_on(glue->phy); > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + phy_set_mode(glue->phy, glue->phy_mode); > > + MUSB_DEV_MODE(musb); > > + break; > > + default: > > + dev_err(glue->dev, "invalid state\n"); > > + } > > +} > > + > > +static int mtk_musb_id_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, id_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + else > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static int mtk_musb_vbus_notifier(struct notifier_block *nb, > > + unsigned long event, void *ptr) > > +{ > > + struct mtk_glue *glue = container_of(nb, struct mtk_glue, vbus_nb); > > + > > + if (event) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > + else > > + mtk_musb_set_mailbox(glue, MTK_VBUS_OFF); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static void mtk_otg_switch_init(struct mtk_glue *glue) > > +{ > > + int ret; > > + > > + /* extcon is optional */ > > + if (!glue->edev) > > + return; > > + > > + glue->vbus_nb.notifier_call = mtk_musb_vbus_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, EXTCON_USB, > > + &glue->vbus_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB\n"); > > + > > + glue->id_nb.notifier_call = mtk_musb_id_notifier; > > + ret = devm_extcon_register_notifier(glue->dev, glue->edev, > > + EXTCON_USB_HOST, &glue->id_nb); > > + if (ret < 0) > > + dev_err(glue->dev, "failed to register notifier for USB-HOST\n"); > > + > > + dev_dbg(glue->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", > > + extcon_get_state(glue->edev, EXTCON_USB), > > + extcon_get_state(glue->edev, EXTCON_USB_HOST)); > > + > > + /* default as host, switch to device mode if needed */ > > + if (extcon_get_state(glue->edev, EXTCON_USB_HOST) == false) > > + mtk_musb_set_mailbox(glue, MTK_ID_FLOAT); > > + if (extcon_get_state(glue->edev, EXTCON_USB) == true) > > + mtk_musb_set_mailbox(glue, MTK_VBUS_VALID); > > +} > > + > > +static irqreturn_t generic_interrupt(int irq, void *__hci) > > +{ > > + unsigned long flags; > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = __hci; > > + > > + spin_lock_irqsave(&musb->lock, flags); > > + musb->int_usb = musb_clearb(musb->mregs, MUSB_INTRUSB); > > + musb->int_rx = musb_clearw(musb->mregs, MUSB_INTRRX); > > + musb->int_tx = musb_clearw(musb->mregs, MUSB_INTRTX); > > + > > + if (musb->int_usb || musb->int_tx || musb->int_rx) > > + retval = musb_interrupt(musb); > > + > > + spin_unlock_irqrestore(&musb->lock, flags); > > + > > + return retval; > > +} > > + > > +static irqreturn_t mtk_musb_interrupt(int irq, void *dev_id) > > +{ > > + irqreturn_t retval = IRQ_NONE; > > + struct musb *musb = (struct musb *)dev_id; > > + u32 l1_ints; > > + > > + l1_ints = musb_readl(musb->mregs, USB_L1INTS) & > > + musb_readl(musb->mregs, USB_L1INTM); > > + > > + if (l1_ints & (TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS)) > > + retval = generic_interrupt(irq, musb); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + if (l1_ints & DMA_INT_STATUS) > > + retval = dma_controller_irq(irq, musb->dma_controller); > > +#endif > > + return retval; > > +} > > + > > +static u32 mtk_musb_busctl_offset(u8 epnum, u16 offset) > > +{ > > + return MTK_MUSB_TXFUNCADDR + offset + 8 * epnum; > > +} > > + > > +static u8 mtk_musb_clearb(void __iomem *addr, unsigned int offset) > > +{ > > + u8 data; > > + > > + /* W1C */ > > + data = musb_readb(addr, offset); > > + musb_writeb(addr, offset, data); > > + return data; > > +} > > + > > +static u16 mtk_musb_clearw(void __iomem *addr, unsigned int offset) > > +{ > > + u16 data; > > + > > + /* W1C */ > > + data = musb_readw(addr, offset); > > + musb_writew(addr, offset, data); > > + return data; > > +} > > + > > +static int mtk_musb_init(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + int ret; > > + > > + glue->musb = musb; > > + musb->phy = glue->phy; > > + musb->xceiv = glue->xceiv; > > + musb->is_host = false; > > + musb->isr = mtk_musb_interrupt; > > + ret = phy_init(glue->phy); > > + if (ret) > > + return ret; > > + > > + ret = phy_power_on(glue->phy); > > + if (ret) { > > + phy_exit(glue->phy); > > + return ret; > > + } > > + > > + phy_set_mode(glue->phy, glue->phy_mode); > > + > > +#if defined(CONFIG_USB_INVENTRA_DMA) > > + musb_writel(musb->mregs, MUSB_HSDMA_INTR, > > + DMA_INTR_STATUS_MSK | DMA_INTR_UNMASK_SET_MSK); > > +#endif > > + musb_writel(musb->mregs, USB_L1INTM, TX_INT_STATUS | RX_INT_STATUS | > > + USBCOM_INT_STATUS | DMA_INT_STATUS); > > + return 0; > > +} > > + > > +static u16 mtk_musb_get_toggle(struct musb_qh *qh, int is_out) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + if (is_out) > > + toggle = musb_readw(musb->mregs, MUSB_TXTOG); > > + else > > + toggle = musb_readw(musb->mregs, MUSB_RXTOG); > > + > > + return toggle & (1 << epnum); > > +} > > + > > +static u16 mtk_musb_set_toggle(struct musb_qh *qh, int is_out, struct urb *urb) > > +{ > > + struct musb *musb = qh->hw_ep->musb; > > + u8 epnum = qh->hw_ep->epnum; > > + u16 toggle; > > + > > + toggle = usb_gettoggle(urb->dev, qh->epnum, is_out); > > + > > + if (is_out) { > > + musb_writew(musb->mregs, MUSB_TXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_TXTOG, (toggle << epnum)); > > + } else { > > + musb_writew(musb->mregs, MUSB_RXTOGEN, (1 << epnum)); > > + musb_writew(musb->mregs, MUSB_RXTOG, (toggle << epnum)); > > + } > > + > > + return 0; > > +} > > + > > +static int mtk_musb_set_mode(struct musb *musb, u8 mode) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + enum phy_mode new_mode; > > + > > + switch (mode) { > > + case MUSB_HOST: > > + new_mode = PHY_MODE_USB_HOST; > > + mtk_musb_set_vbus(musb, 1); > > + break; > > + case MUSB_PERIPHERAL: > > + new_mode = PHY_MODE_USB_DEVICE; > > + break; > > + case MUSB_OTG: > > + new_mode = PHY_MODE_USB_HOST; > > + break; > > + default: > > + dev_err(musb->controller->parent, > > + "Error requested mode not supported by this kernel\n"); > > + return -EINVAL; > > + } > > + if (glue->phy_mode == new_mode) > > + return 0; > > + > > + mtk_musb_set_mailbox(glue, MTK_ID_GROUND); > > + return 0; > > +} > > + > > +static int mtk_musb_exit(struct musb *musb) > > +{ > > + struct device *dev = musb->controller; > > + struct mtk_glue *glue = dev_get_drvdata(dev->parent); > > + > > + phy_power_off(glue->phy); > > + phy_exit(glue->phy); > > + mtk_musb_clks_disable(glue); > > + > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > + return 0; > > +} > > + > > +static const struct musb_platform_ops mtk_musb_ops = { > > + .quirks = MUSB_DMA_INVENTRA, > > + .init = mtk_musb_init, > > + .get_toggle = mtk_musb_get_toggle, > > + .set_toggle = mtk_musb_set_toggle, > > + .exit = mtk_musb_exit, > > +#ifdef CONFIG_USB_INVENTRA_DMA > > + .dma_init = musbhs_dma_controller_create_noirq, > > + .dma_exit = musbhs_dma_controller_destroy, > > +#endif > > + .clearb = mtk_musb_clearb, > > + .clearw = mtk_musb_clearw, > > + .busctl_offset = mtk_musb_busctl_offset, > > + .set_mode = mtk_musb_set_mode, > > + .set_vbus = mtk_musb_set_vbus, > > +}; > > + > > +#define MTK_MUSB_MAX_EP_NUM 8 > > +#define MTK_MUSB_RAM_BITS 11 > > + > > +static struct musb_fifo_cfg mtk_musb_mode_cfg[] = { > > + { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, > > + { .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 1024, }, > > + { .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 1024, }, > > + { .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, > > + { .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 64, }, > > +}; > > + > > +static const struct musb_hdrc_config mtk_musb_hdrc_config = { > > + .fifo_cfg = mtk_musb_mode_cfg, > > + .fifo_cfg_size = ARRAY_SIZE(mtk_musb_mode_cfg), > > + .multipoint = true, > > + .dyn_fifo = true, > > + .num_eps = MTK_MUSB_MAX_EP_NUM, > > + .ram_bits = MTK_MUSB_RAM_BITS, > > +}; > > + > > +static const struct platform_device_info mtk_dev_info = { > > + .name = "musb-hdrc", > > + .id = PLATFORM_DEVID_AUTO, > > + .dma_mask = DMA_BIT_MASK(32), > > +}; > > + > > +static int mtk_musb_probe(struct platform_device *pdev) > > +{ > > + struct musb_hdrc_platform_data *pdata; > > + struct mtk_glue *glue; > > + struct platform_device_info pinfo; > > + struct device *dev = &pdev->dev; > > + struct device_node *np = dev->of_node; > > + struct device_node *child, *extcon_node; > > + int ret = -ENOMEM; > > + > > + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); > > + if (!glue) > > + return -ENOMEM; > > + > > + glue->dev = dev; > > + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); > > + if (!pdata) > > + return -ENOMEM; > > + > > + ret = mtk_musb_clks_get(glue); > > + if (ret) > > + return ret; > > + > > + pdata->config = &mtk_musb_hdrc_config; > > + pdata->platform_ops = &mtk_musb_ops; > > + > > + glue->vbus = devm_regulator_get(dev, "vbus"); > > + if (IS_ERR(glue->vbus)) { > > + dev_err(dev, "fail to get vbus\n"); > > + return PTR_ERR(glue->vbus); > > + } > > + > > + child = of_get_child_by_name(np, "connector"); > > + if (!child) { > > + dev_err(dev, "failed to find usb connector node\n"); > > + return ERR_PTR(-ENODEV); > > The 'probe' function is returning an 'int' and not a pointer. This > line should trigger a warning. OK, thanks. > > + } > > + > > + extcon_node = of_parse_phandle(child, "extcon", 0); > > + if (!extcon_node) { > > + dev_err(dev, "failed to get extcon phandle"); > > + return ERR_PTR(-ENODEV); > > Same here OK, thanks. > > + } > > + > > + glue->edev = extcon_find_edev_by_node(extcon_node); > > + if (IS_ERR(glue->edev)) { > > + dev_err(dev, "fail to get extcon\n"); > > + return PTR_ERR(glue->edev); > > + } > > + > > + pdata->mode = usb_get_dr_mode(dev); > > + switch (pdata->mode) { > > + case USB_DR_MODE_HOST: > > + glue->phy_mode = PHY_MODE_USB_HOST; > > + break; > > + case USB_DR_MODE_PERIPHERAL: > > + glue->phy_mode = PHY_MODE_USB_DEVICE; > > + break; > > + default: > > + pdata->mode = USB_DR_MODE_OTG; > > + /* FALL THROUGH */ > > + case USB_DR_MODE_OTG: > > + glue->phy_mode = PHY_MODE_USB_OTG; > > + break; > > + } > > + > > + glue->phy = devm_of_phy_get_by_index(dev, np, 0); > > + if (IS_ERR(glue->phy)) { > > + dev_err(dev, "fail to getting phy %ld\n", > > + PTR_ERR(glue->phy)); > > + return PTR_ERR(glue->phy); > > + } > > + > > + glue->usb_phy = usb_phy_generic_register(); > > + if (IS_ERR(glue->usb_phy)) { > > + dev_err(dev, "fail to registering usb-phy %ld\n", > > + PTR_ERR(glue->usb_phy)); > > + return PTR_ERR(glue->usb_phy); > > + } > > + > > + glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); > > + if (IS_ERR(glue->xceiv)) { > > + dev_err(dev, "fail to getting usb-phy %d\n", ret); > > + ret = PTR_ERR(glue->xceiv); > > + goto err_unregister_usb_phy; > > + } > > + > > + platform_set_drvdata(pdev, glue); > > + pm_runtime_enable(dev); > > + pm_runtime_get_sync(dev); > > + > > + ret = mtk_musb_clks_enable(glue); > > + if (ret) > > + goto err_enable_clk; > > + > > + pinfo = mtk_dev_info; > > + pinfo.parent = dev; > > + pinfo.res = pdev->resource; > > + pinfo.num_res = pdev->num_resources; > > + pinfo.data = pdata; > > + pinfo.size_data = sizeof(*pdata); > > + > > + glue->musb_pdev = platform_device_register_full(&pinfo); > > + if (IS_ERR(glue->musb_pdev)) { > > + ret = PTR_ERR(glue->musb_pdev); > > + dev_err(dev, "failed to register musb device: %d\n", ret); > > + goto err_device_register; > > + } > > + > > + if (pdata->mode == USB_DR_MODE_OTG) > > + mtk_otg_switch_init(glue); > > + > > + return 0; > > + > > +err_device_register: > > + mtk_musb_clks_disable(glue); > > +err_enable_clk: > > + pm_runtime_put_sync(dev); > > + pm_runtime_disable(dev); > > +err_unregister_usb_phy: > > + usb_phy_generic_unregister(glue->usb_phy); > > + return ret; > > +} > > + > > +static int mtk_musb_remove(struct platform_device *pdev) > > +{ > > + struct mtk_glue *glue = platform_get_drvdata(pdev); > > + struct platform_device *usb_phy = glue->usb_phy; > > + > > + platform_device_unregister(glue->musb_pdev); > > + usb_phy_generic_unregister(usb_phy); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_OF > > +static const struct of_device_id mtk_musb_match[] = { > > + {.compatible = "mediatek,mtk-musb",}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, mtk_musb_match); > > +#endif > > + > > +static struct platform_driver mtk_musb_driver = { > > + .probe = mtk_musb_probe, > > + .remove = mtk_musb_remove, > > + .driver = { > > + .name = "musb-mtk", > > + .of_match_table = of_match_ptr(mtk_musb_match), > > + }, > > +}; > > + > > +module_platform_driver(mtk_musb_driver); > > + > > +MODULE_DESCRIPTION("MediaTek MUSB Glue Layer"); > > +MODULE_AUTHOR("Min Guo "); > > +MODULE_LICENSE("GPL v2"); > > -- > > 1.9.1 > > > > > > _______________________________________________ > > linux-arm-kernel mailing list > > linux-arm-kernel@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel