This a a copy of the whole dir which fixes HiSilicon changes to usb and gadget.
Signed-off-by: Lukasz Luba <l.luba@partner.samsung.com>
source "drivers/usb/isp1760/Kconfig"
-source "drivers/usb/pd/Kconfig"
-
comment "USB port drivers"
if USB
obj-$(CONFIG_TYPEC) += typec/
obj-$(CONFIG_USB_ROLE_SWITCH) += roles/
-
-obj-$(CONFIG_TCPC_CLASS) += pd/
for peripheral mode support.
Say 'Y' or 'M' if you have one such device.
-config USB_DWC3_HISI
- tristate "Hisilicon Platforms"
- select USB_DWC3_OTG
- default USB_DWC3
- help
- Support of USB2/3 functionality in hisilicon platforms,
- Say 'Y' or 'M' here if you have one such device.
- Use for hisilicon device and it will select USB_DWC3_OTG
- if Say 'Y' or 'M' here.
-
-config USB_DWC3_OTG
- bool "Enable DWC3 OTG"
- default n
- help
- Say Y here to enable DWC3 OTG feature.
endif
# define_trace.h needs to know how to find our header
CFLAGS_trace.o := -I$(src)
-ccflags-$(CONFIG_USB_DWC3_HISI) += -DDWC3_ENABLE_CSP
-ccflags-$(CONFIG_USB_DWC3_OTG) += -DDWC3_OTG_FORCE_MODE
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
dwc3-y += debugfs.o
endif
-dwc3-$(CONFIG_USB_DWC3_OTG) += dwc3-otg.o
-
##
# Platform-specific glue layers go here
#
obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o
obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o
-obj-$(CONFIG_USB_DWC3_HISI) += dwc3-hisi.o dwc3-hi3660.o
#include "core.h"
#include "gadget.h"
#include "io.h"
-#include "dwc3-otg.h"
+
#include "debug.h"
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
mode = USB_DR_MODE_PERIPHERAL;
- else if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE))
- mode = USB_DR_MODE_OTG;
}
if (mode != dwc->dr_mode) {
dwc->current_dr_role = mode;
}
-#ifndef CONFIG_USB_DWC3_HISI
static void __dwc3_set_mode(struct work_struct *work)
{
struct dwc3 *dwc = work_to_dwc(work);
}
}
-#endif
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
evt = dwc->ev_buf;
evt->lpos = 0;
- #ifdef CONFIG_USB_DWC3_HISI
- evt->count = 0;
- evt->flags = 0;
- memset(evt->buf, 0, evt->length);
- #endif
-
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
lower_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
*/
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
- #ifdef DWC3_OTG_FORCE_MODE
- /*
- * if ID status is detected by third module, default device mode.
- */
- reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
- reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
- #endif
+
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
phy_calibrate(dwc->usb2_generic_phy);
break;
case USB_DR_MODE_OTG:
- #ifndef CONFIG_USB_DWC3_HISI
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
ret = dwc3_drd_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize dual-role\n");
return ret;
}
- #else
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
-
- ret = dwc3_hisi_otg_init(dwc);
- if (ret) {
- dev_err(dev, "failed to initialize otg\n");
- return ret;
- }
-
- ret = dwc3_host_init(dwc);
- if (ret) {
- dev_err(dev, "failed to initialize host\n");
- dwc3_otg_exit(dwc);
- return ret;
- }
-
- ret = dwc3_gadget_init(dwc);
- if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
- dwc3_host_exit(dwc);
- dwc3_otg_exit(dwc);
- return ret;
- }
- #endif
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
break;
case USB_DR_MODE_OTG:
dwc3_drd_exit(dwc);
- dwc3_otg_exit(dwc);
break;
default:
/* do nothing */
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- case DWC3_GCTL_PRTCAP_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
if (!PMSG_IS_AUTO(msg)) {
phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
break;
-#if 0
case DWC3_GCTL_PRTCAP_OTG:
/* do nothing during runtime_suspend */
if (PMSG_IS_AUTO(msg))
dwc3_otg_exit(dwc);
dwc3_core_exit(dwc);
break;
-#endif
default:
/* do nothing */
break;
}
- dwc3_core_exit(dwc);
-
return 0;
}
int ret;
u32 reg;
- ret = dwc3_core_init(dwc);
- if (ret)
- return ret;
-
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;
- case DWC3_GCTL_PRTCAP_OTG:
+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
phy_pm_runtime_get_sync(dwc->usb2_generic_phy);
phy_pm_runtime_get_sync(dwc->usb3_generic_phy);
break;
-#if 0
+ case DWC3_GCTL_PRTCAP_OTG:
/* nothing to do on runtime_resume */
if (PMSG_IS_AUTO(msg))
break;
}
break;
-#endif
default:
/* do nothing */
break;
{
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- case DWC3_GCTL_PRTCAP_OTG:
-#ifndef CONFIG_USB_DWC3_HISI
if (dwc->connected)
return -EBUSY;
-#endif
break;
case DWC3_GCTL_PRTCAP_HOST:
default:
device_init_wakeup(dev, true);
- pm_runtime_put(dev);
return 0;
}
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- case DWC3_GCTL_PRTCAP_OTG:
dwc3_gadget_process_pending_events(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
}
pm_runtime_mark_last_busy(dev);
- pm_runtime_get(dev);
return 0;
}
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
- case DWC3_GCTL_PRTCAP_OTG:
if (dwc3_runtime_checks(dwc))
return -EBUSY;
break;
static const struct dev_pm_ops dwc3_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
- dwc3_runtime_idle)
+ dwc3_runtime_idle)
};
-int dwc3_resume_device(struct dwc3 *dwc)
-{
- int status;
-
- pr_info("[dwc3_resume_device] +\n");
- status = dwc3_runtime_resume(dwc->dev);
- if (status < 0) {
- pr_err("dwc3_runtime_resume err, status:%d\n", status);
- }
- pr_info("[dwc3_resume_device] -\n");
- return status;
-}
-
-void dwc3_suspend_device(struct dwc3 *dwc)
-{
- int status;
-
- pr_info("[dwc3_suspend_device] +\n");
- status = dwc3_runtime_suspend(dwc->dev);
- if (status < 0) {
- pr_err("dwc3_runtime_suspend err, status:%d\n", status);
- }
- pr_info("[dwc3_suspend_device] -\n");
-}
-
#ifdef CONFIG_OF
static const struct of_device_id of_dwc3_match[] = {
{
unsigned mapped:1;
unsigned started:1;
unsigned zero:1;
- unsigned send_zlp:1;
};
/*
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};
-struct dwc3_otg;
-
/**
* struct dwc3 - representation of our controller
* @drd_work: workqueue used for role swapping
u8 tx_thr_num_pkt_prd;
u8 tx_max_burst_prd;
- struct dwc3_otg *dwc_otg;
const char *hsphy_interface;
unsigned connected:1;
unsigned delayed_status:1;
-
- /* the delayed status may come before notready interrupt,
- * in this case, don't wait for delayed status
- */
- unsigned status_queued:1;
-
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
unsigned has_hibernation:1;
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
-void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
+
/* check whether we are on the DWC_usb3 core */
static inline bool dwc3_is_usb3(struct dwc3 *dwc)
{
int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
struct dwc3_gadget_ep_cmd_params *params);
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
-int dwc3_conndone_notifier_register(struct notifier_block *nb);
-int dwc3_conndone_notifier_unregister(struct notifier_block *nb);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc)
{ return 0; }
static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
int cmd, u32 param)
{ return 0; }
-static inline int dwc3_conndone_notifier_register(struct notifier_block *nb)
-{ return 0; }
-static inline int dwc3_conndone_notifier_unregister(struct notifier_block *nb)
-{ return 0; }
#endif
#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
}
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
-int dwc3_resume_device(struct dwc3 *dwc);
-void dwc3_suspend_device(struct dwc3 *dwc);
-
#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
int dwc3_ulpi_init(struct dwc3 *dwc);
void dwc3_ulpi_exit(struct dwc3 *dwc);
+++ /dev/null
-/*
- * dwc3-hi3660.c
- *
- * Copyright: (C) 2008-2018 hisilicon.
- * Contact: wangbinghui<wangbinghui@hisilicon.com>
- *
- * USB vbus for Hisilicon device
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose this file to be licensed under the terms
- * of the GNU General Public License (GPL) Version 2 or the 2-clause
- * BSD license listed below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- */
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-
-#include "dwc3-hisi.h"
-
-/*lint -e750 -esym(750,*)*/
-/* clk module will round to 228M */
-#define USB3OTG_ACLK_FREQ 229000000
-#ifndef BIT
-#define BIT(x) (1 << (x))
-#endif
-#define SCTRL_SCDEEPSLEEPED 0x08
-#define USB_REFCLK_ISO_EN BIT(25)
-#define PCTRL_PERI_CTRL3 0x10
-#define USB_TCXO_EN BIT(1)
-#define PERI_CTRL3_MSK_START (16)
-#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25)
-
-#define SC_SEL_ABB_BACKUP BIT(8)
-#define CLKDIV_MASK_START (16)
-
-#define PERI_CRG_CLKDIV21 0xFC
-
-#define GT_CLK_ABB_BACKUP BIT(22)
-#define PERI_CRG_CLK_DIS5 0x54
-
-#define PMC_PPLL3CTRL0 0x048
-#define PPLL3_FBDIV_START (8)
-#define PPLL3_EN BIT(0)
-#define PPLL3_BP BIT(1)
-#define PPLL3_LOCK BIT(26)
-
-#define PMC_PPLL3CTRL1 0x04C
-#define PPLL3_INT_MOD BIT(24)
-#define GT_CLK_PPLL3 BIT(26)
-
-#define PERI_CRG_CLK_EN5 0x50
-
-#define SC_USB3PHY_ABB_GT_EN BIT(15)
-#define REF_SSP_EN BIT(16)
-/*lint -e750 +esym(750,*)*/
-
-static int usb3_regu_init(struct hisi_dwc3_device *hisi_dwc3)
-{
- if (hisi_dwc3->is_regu_on != 0) {
- usb_dbg("ldo already opened!\n");
- return 0;
- }
-
- hisi_dwc3->is_regu_on = 1;
-
- return 0;
-}
-
-static int usb3_regu_shutdown(struct hisi_dwc3_device *hisi_dwc3)
-{
- if (hisi_dwc3->is_regu_on == 0) {
- usb_dbg("regu already closed!\n");
- return 0;
- }
-
- hisi_dwc3->is_regu_on = 0;
-
- return 0;
-}
-
-static int usb3_clk_init(struct hisi_dwc3_device *hisi_dwc3)
-{
- int ret;
- u32 temp;
- void __iomem *pctrl_base = hisi_dwc3->pctrl_reg_base;
- void __iomem *pericfg_base = hisi_dwc3->pericfg_reg_base;
-
- /* set usb aclk 240MHz to improve performance */
- ret = clk_set_rate(hisi_dwc3->gt_aclk_usb3otg, USB3OTG_ACLK_FREQ);
- if (ret)
- usb_err("usb aclk set rate failed\n");
-
- ret = clk_prepare_enable(hisi_dwc3->gt_aclk_usb3otg);
- if (ret) {
- usb_err("clk_prepare_enable gt_aclk_usb3otg failed\n");
- return ret;
- }
-
- /* usb refclk iso enable */
- writel(USB_REFCLK_ISO_EN, pericfg_base + PERI_CRG_ISODIS);
-
- /* enable usb_tcxo_en */
- writel(USB_TCXO_EN | (USB_TCXO_EN << PERI_CTRL3_MSK_START),
- pctrl_base + PCTRL_PERI_CTRL3);
-
- /* select usbphy clk from abb */
- temp = readl(pctrl_base + PCTRL_PERI_CTRL24);
- temp &= ~SC_CLK_USB3PHY_3MUX1_SEL;
- writel(temp, pctrl_base + PCTRL_PERI_CTRL24);
-
- /* open clk gate */
- writel(GT_CLK_USB3OTG_REF | GT_ACLK_USB3OTG,
- pericfg_base + PERI_CRG_CLK_EN4);
-
- ret = clk_prepare_enable(hisi_dwc3->clk);
- if (ret) {
- usb_err("clk_prepare_enable clk failed\n");
- return ret;
- }
-
- return 0;
-}
-
-static void usb3_clk_shutdown(struct hisi_dwc3_device *hisi_dwc3)
-{
- u32 temp;
- void __iomem *pctrl_base = hisi_dwc3->pctrl_reg_base;
- void __iomem *pericfg_base = hisi_dwc3->pericfg_reg_base;
-
- writel(GT_CLK_USB3OTG_REF | GT_ACLK_USB3OTG,
- pericfg_base + PERI_CRG_CLK_DIS4);
-
- temp = readl(pctrl_base + PCTRL_PERI_CTRL24);
- temp &= ~SC_CLK_USB3PHY_3MUX1_SEL;
- writel(temp, pctrl_base + PCTRL_PERI_CTRL24);
-
- /* disable usb_tcxo_en */
- writel(0 | (USB_TCXO_EN << PERI_CTRL3_MSK_START),
- pctrl_base + PCTRL_PERI_CTRL3);
-
- clk_disable_unprepare(hisi_dwc3->clk);
- clk_disable_unprepare(hisi_dwc3->gt_aclk_usb3otg);
-
- msleep(20);
-}
-
-static void dwc3_release(struct hisi_dwc3_device *hisi_dwc3)
-{
- u32 temp;
- void __iomem *pericfg_base = hisi_dwc3->pericfg_reg_base;
- void __iomem *otg_bc_base = hisi_dwc3->otg_bc_reg_base;
-
- /* dis-reset the module */
- writel(IP_RST_USB3OTG_MUX | IP_RST_USB3OTG_AHBIF | IP_RST_USB3OTG_32K,
- pericfg_base + PERI_CRG_RSTDIS4);
-
- /* reset phy */
- writel(IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG,
- pericfg_base + PERI_CRG_RSTEN4);
-
- /* enable phy ref clk */
- temp = readl(otg_bc_base + USBOTG3_CTRL0);
- temp |= SC_USB3PHY_ABB_GT_EN;
- writel(temp, otg_bc_base + USBOTG3_CTRL0);
-
- temp = readl(otg_bc_base + USBOTG3_CTRL7);
- temp |= REF_SSP_EN;
- writel(temp, otg_bc_base + USBOTG3_CTRL7);
-
- /* exit from IDDQ mode */
- temp = readl(otg_bc_base + USBOTG3_CTRL2);
- temp &= ~(USBOTG3CTRL2_POWERDOWN_HSP | USBOTG3CTRL2_POWERDOWN_SSP);
- writel(temp, otg_bc_base + USBOTG3_CTRL2);
-
- usleep_range(100, 120);
-
- /* dis-reset phy */
- writel(IP_RST_USB3OTGPHY_POR, pericfg_base + PERI_CRG_RSTDIS4);
-
- /* dis-reset controller */
- writel(IP_RST_USB3OTG, pericfg_base + PERI_CRG_RSTDIS4);
-
- msleep(20);
-
- /* fake vbus valid signal */
- temp = readl(otg_bc_base + USBOTG3_CTRL3);
- temp |= (USBOTG3_CTRL3_VBUSVLDEXT | USBOTG3_CTRL3_VBUSVLDEXTSEL);
- writel(temp, otg_bc_base + USBOTG3_CTRL3);
-
- usleep_range(100, 120);
-}
-
-static void dwc3_reset(struct hisi_dwc3_device *hisi_dwc3)
-{
- void __iomem *pericfg_base = hisi_dwc3->pericfg_reg_base;
-
- writel(IP_RST_USB3OTG, pericfg_base + PERI_CRG_RSTEN4);
- writel(IP_RST_USB3OTGPHY_POR, pericfg_base + PERI_CRG_RSTEN4);
- writel(IP_RST_USB3OTG_MUX | IP_RST_USB3OTG_AHBIF | IP_RST_USB3OTG_32K,
- pericfg_base + PERI_CRG_RSTEN4);
-}
-
-static int hi3660_usb3phy_init(struct hisi_dwc3_device *hisi_dwc3)
-{
- int ret;
-
- usb_dbg("+\n");
-
- ret = usb3_regu_init(hisi_dwc3);
- if (ret)
- return ret;
-
- ret = usb3_clk_init(hisi_dwc3);
- if (ret)
- return ret;
-
- dwc3_release(hisi_dwc3);
- config_femtophy_param(hisi_dwc3);
-
- set_hisi_dwc3_power_flag(1);
-
- usb_dbg("-\n");
-
- return 0;
-}
-
-static int hi3660_usb3phy_shutdown(struct hisi_dwc3_device *hisi_dwc3)
-{
- int ret;
-
- usb_dbg("+\n");
-
- set_hisi_dwc3_power_flag(0);
-
- dwc3_reset(hisi_dwc3);
- usb3_clk_shutdown(hisi_dwc3);
-
- ret = usb3_regu_shutdown(hisi_dwc3);
- if (ret)
- return ret;
-
- usb_dbg("-\n");
-
- return 0;
-}
-
-static struct usb3_phy_ops hi3660_phy_ops = {
- .init = hi3660_usb3phy_init,
- .shutdown = hi3660_usb3phy_shutdown,
-};
-
-static int dwc3_hi3660_probe(struct platform_device *pdev)
-{
- int ret = 0;
-
- ret = hisi_dwc3_probe(pdev, &hi3660_phy_ops);
- if (ret)
- usb_err("probe failed, ret=[%d]\n", ret);
-
- return ret;
-}
-
-static int dwc3_hi3660_remove(struct platform_device *pdev)
-{
- int ret = 0;
-
- ret = hisi_dwc3_remove(pdev);
- if (ret)
- usb_err("hisi_dwc3_remove failed, ret=[%d]\n", ret);
-
- return ret;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id dwc3_hi3660_match[] = {
- { .compatible = "hisilicon,hi3660-dwc3" },
- {},
-};
-MODULE_DEVICE_TABLE(of, dwc3_hi3660_match);
-#else
-#define dwc3_hi3660_match NULL
-#endif
-
-static struct platform_driver dwc3_hi3660_driver = {
- .probe = dwc3_hi3660_probe,
- .remove = dwc3_hi3660_remove,
- .driver = {
- .name = "usb3-hi3660",
- .of_match_table = of_match_ptr(dwc3_hi3660_match),
- .pm = HISI_DWC3_PM_OPS,
- },
-};
-
-module_platform_driver(dwc3_hi3660_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("DesignWare USB3 HI3660 Glue Layer");
-MODULE_AUTHOR("wangbinghui<wangbinghui@hisilicon.com>");
+++ /dev/null
-/*
- * hisi_usb_vbus.c
- *
- * Copyright: (C) 2008-2018 hisilicon.
- * Contact: wangbinghui<wangbinghui@hisilicon.com>
- *
- * USB vbus for Hisilicon device
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose this file to be licensed under the terms
- * of the GNU General Public License (GPL) Version 2 or the 2-clause
- * BSD license listed below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/of_gpio.h>
-#include <linux/usb/ch9.h>
-
-#include "dwc3-hisi.h"
-#include "core.h"
-#include "dwc3-otg.h"
-
-#define ENABLE_USB_TEST_PORT
-
-#define BC_AGAIN_DELAY_TIME 8000 /* ms */
-
-struct hisi_dwc3_device *hisi_dwc3_dev;
-atomic_t hisi_dwc3_power_on = ATOMIC_INIT(0);
-
-void set_hisi_dwc3_power_flag(int val)
-{
- unsigned long flags;
- struct dwc3 *dwc = NULL;
-
- if (dwc_otg_handler && dwc_otg_handler->dwc) {
- dwc = dwc_otg_handler->dwc;
- spin_lock_irqsave(&dwc->lock, flags);
- usb_dbg("get dwc3 lock\n");
- }
-
- atomic_set(&hisi_dwc3_power_on, val);
- usb_dbg("set hisi_dwc3_power_flag %d\n", val);
-
- if (dwc) {
- spin_unlock_irqrestore(&dwc->lock, flags);
- usb_dbg("put dwc3 lock\n");
- }
-}
-
-#ifdef ENABLE_USB_TEST_PORT
-
-static ssize_t plugusb_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct hisi_dwc3_device *hisi_dwc3 = platform_get_drvdata(pdev);
- char *s;
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return scnprintf(buf, PAGE_SIZE, "hisi_dwc3 NULL\n");
- }
-
- switch (hisi_dwc3->state) {
- case USB_STATE_UNKNOWN:
- s = "USB_STATE_UNKNOWN";
- break;
- case USB_STATE_OFF:
- s = "USB_STATE_OFF";
- break;
- case USB_STATE_DEVICE:
- s = "USB_STATE_DEVICE";
- break;
- case USB_STATE_HOST:
- s = "USB_STATE_HOST";
- break;
- default:
- s = "unknown";
- break;
- }
- return scnprintf(buf, PAGE_SIZE, "current state: %s\n usage: %s\n", s,
- "echo hoston/hostoff/deviceon/deviceoff > plugusb\n");
-}
-
-static ssize_t plugusb_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- if (!strncmp(buf, "hoston", strlen("hoston")))
- hisi_usb_otg_event(ID_FALL_EVENT);
- else if (!strncmp(buf, "hostoff", strlen("hostoff")))
- hisi_usb_otg_event(ID_RISE_EVENT);
- else if (!strncmp(buf, "deviceon", strlen("deviceon")))
- hisi_usb_otg_event(CHARGER_CONNECT_EVENT);
- else if (!strncmp(buf, "deviceoff", strlen("deviceoff")))
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- else
- usb_err("input state is ilegal!\n");
-
- /* added for show message of plugusb status to com port */
- pr_err("[USB.plugusb] %s\n", buf);
-
- return size;
-}
-
-/*lint -save -e750 */
-DEVICE_ATTR(plugusb, (0644), plugusb_show, plugusb_store);
-/*lint -restore */
-
-static const char * const charger_type_array[] = {
- [CHARGER_TYPE_SDP] = "sdp", /* Standard Downstreame Port */
- [CHARGER_TYPE_CDP] = "cdp", /* Charging Downstreame Port */
- [CHARGER_TYPE_DCP] = "dcp", /* Dedicate Charging Port */
- [CHARGER_TYPE_UNKNOWN] = "unknown", /* non-standard */
- [CHARGER_TYPE_NONE] = "none", /* not connected */
- [PLEASE_PROVIDE_POWER] = "provide" /* host mode, provide power */
-};
-
-static enum hisi_charger_type get_charger_type_from_str(const char *buf,
- size_t size)
-{
- int i = 0;
- enum hisi_charger_type ret = CHARGER_TYPE_NONE;
-
- for (i = 0; i < sizeof(charger_type_array) /
- sizeof(charger_type_array[0]); i++) {
- if (!strncmp(buf, charger_type_array[i], size - 1)) {
- ret = (enum hisi_charger_type)i;
- break;
- }
- }
-
- return ret;
-}
-
-ssize_t hiusb_do_charger_show(void *dev_data, char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
- enum hisi_charger_type charger_type = CHARGER_TYPE_NONE;
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return scnprintf(buf, size,
- "platform_get_drvdata return null\n");
- }
-
- mutex_lock(&hisi_dwc->lock);
- charger_type = hisi_dwc->charger_type;
- mutex_unlock(&hisi_dwc->lock);
-
- return scnprintf(buf, size, "[(%d):Charger type = %s]\n"
- "----------------------------------------------------------------\n"
- "usage: echo {str} > chargertest\n"
- " sdp: Standard Downstreame Port\n"
- " cdp: Charging Downstreame Port\n"
- " dcp: Dedicate Charging Port\n"
- " unknown: non-standard\n"
- " none: not connected\n"
- " provide: host mode, provide power\n"
- , charger_type, charger_type_array[charger_type]);
-}
-
-int hiusb_get_eyepattern_param(void *dev_data, char *buf, size_t len)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
- int ret = 0;
-
- if (hisi_dwc) {
- ret = scnprintf(buf, len, "device:0x%x\nhost:0x%x\n",
- hisi_dwc->eye_diagram_param,
- hisi_dwc->eye_diagram_host_param);
- } else {
- usb_err("hisi_dwc NULL\n");
- ret = scnprintf(buf, len, "hisi_dwc NULL\n");
- }
-
- return ret;
-}
-
-int hiusb_set_eyepattern_param(void *dev_data, const char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
- int eye_diagram_param;
-
- if (!hisi_dwc) {
- pr_err("seteye: hisi_dwc is null\n");
- return size;
- }
-
- if (sscanf(buf, "%32x", &eye_diagram_param) != 1)
- return size;
-
- hisi_dwc->eye_diagram_param = eye_diagram_param;
- hisi_dwc->eye_diagram_host_param = eye_diagram_param;
-
- return size;
-}
-
-static void notify_charger_type(struct hisi_dwc3_device *hisi_dwc3);
-ssize_t hiusb_do_charger_store(void *dev_data, const char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
- enum hisi_charger_type charger_type =
- get_charger_type_from_str(buf, size);
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return size;
- }
-
- mutex_lock(&hisi_dwc->lock);
- hisi_dwc->charger_type = charger_type;
- notify_charger_type(hisi_dwc);
- mutex_unlock(&hisi_dwc->lock);
-
- return size;
-}
-
-#ifdef CONFIG_HISI_DEBUG_FS
-static ssize_t fakecharger_show(void *dev_data, char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return scnprintf(buf, size,
- "platform_get_drvdata return null\n");
- }
-
- return scnprintf(buf, size, "[fake charger type: %s]\n",
- hisi_dwc->fake_charger_type == CHARGER_TYPE_NONE ?
- "not fake" :
- charger_type_array[hisi_dwc->fake_charger_type]);
-}
-
-static ssize_t fakecharger_store(void *dev_data, const char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
- enum hisi_charger_type charger_type =
- get_charger_type_from_str(buf, size);
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return size;
- }
-
- mutex_lock(&hisi_dwc->lock);
- hisi_dwc->fake_charger_type = charger_type;
- mutex_unlock(&hisi_dwc->lock);
-
- return size;
-}
-#endif
-ssize_t hiusb_do_eventmask_show(void *dev_data, char *buf, size_t size)
-{
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return scnprintf(buf, size,
- "platform_get_drvdata return null\n");
- }
-
- return scnprintf(buf, size, "%d\n", hisi_dwc->eventmask);
-}
-
-ssize_t hiusb_do_eventmask_store(void *dev_data, const char *buf, size_t size)
-{
- int eventmask;
- struct hisi_dwc3_device *hisi_dwc = (struct hisi_dwc3_device *)dev_data;
-
- if (!hisi_dwc) {
- pr_err("platform_get_drvdata return null\n");
- return size;
- }
-
- if (sscanf(buf, "%1d", &eventmask) != 1)
- return size;
-
- hisi_dwc->eventmask = eventmask;
-
- return size;
-}
-
-static struct device_attribute *hisi_dwc3_attributes[] = {
- &dev_attr_plugusb,
- NULL
-};
-
-static int create_attr_file(struct device *dev)
-{
- struct device_attribute **attrs = hisi_dwc3_attributes;
- struct device_attribute *attr;
- struct class *hisi_usb_class;
- struct device *hisi_usb_dev;
- int i;
- int ret = 0;
-
- usb_dbg("+\n");
- for (i = 0; attrs[i]; i++) {
- attr = attrs[i];
- ret = device_create_file(dev, attr);
- if (ret) {
- dev_err(dev, "create attr file error!\n");
- goto err;
- }
- }
-
- hisi_usb_class = class_create(THIS_MODULE, "hisi_usb_class");
- if (IS_ERR(hisi_usb_class)) {
- usb_dbg("create hisi_usb_class error!\n");
- } else {
- hisi_usb_dev = device_create(hisi_usb_class, NULL, 0,
- NULL, "hisi_usb_dev");
- if (IS_ERR(hisi_usb_dev))
- usb_dbg("create hisi_usb_dev error!\n");
- else
- ret |= sysfs_create_link(&hisi_usb_dev->kobj,
- &dev->kobj, "interface");
- }
- if (ret)
- usb_dbg("create attr file error!\n");
-
-#ifdef CONFIG_HISI_DEBUG_FS
- hiusb_debug_quick_register(
- platform_get_drvdata(to_platform_device(dev)),
- (hiusb_debug_show_ops)fakecharger_show,
- (hiusb_debug_store_ops)fakecharger_store);
- hiusb_debug_init(platform_get_drvdata(to_platform_device(dev)));
-#endif
-
- usb_dbg("-\n");
- return 0;
-
-err:
- for (i-- ; i >= 0; i--) {
- attr = attrs[i];
- device_remove_file(dev, attr);
- }
-
- return ret;
-}
-
-static void remove_attr_file(struct device *dev)
-{
- struct device_attribute **attrs = hisi_dwc3_attributes;
- struct device_attribute *attr;
-
- while ((attr = *attrs++))
- device_remove_file(dev, attr);
-}
-#else
-static inline int create_attr_file(struct device *dev)
-{
- return 0;
-}
-
-static inline void remove_attr_file(struct device *dev) {}
-#endif
-
-static void phy_cr_wait_ack(void __iomem *otg_bc_base)
-{
- int i = 1000;
-
- while (1) {
- if ((readl(otg_bc_base + USB3PHY_CR_STS) &
- USB3OTG_PHY_CR_ACK) == 1)
- break;
- usleep_range(50, 60);
- if (i-- < 0) {
- usb_err("wait phy_cr_ack timeout!\n");
- break;
- }
- }
-}
-
-static void phy_cr_set_addr(void __iomem *otg_bc_base, u32 addr)
-{
- u32 reg;
-
- /* set addr */
- reg = USB3OTG_PHY_CR_DATA_IN(addr);
- writel(reg, otg_bc_base + USB3PHY_CR_CTRL);
-
- usleep_range(100, 120);
-
- /* cap addr */
- reg = readl(otg_bc_base + USB3PHY_CR_CTRL);
- reg |= USB3OTG_PHY_CR_CAP_ADDR;
- writel(reg, otg_bc_base + USB3PHY_CR_CTRL);
-
- phy_cr_wait_ack(otg_bc_base);
-
- /* clear ctrl reg */
- writel(0, otg_bc_base + USB3PHY_CR_CTRL);
-}
-
-static u16 phy_cr_read(void __iomem *otg_bc_base, u32 addr)
-{
- u32 reg;
- int i = 1000;
-
- phy_cr_set_addr(otg_bc_base, addr);
-
- /* read cap */
- writel(USB3OTG_PHY_CR_READ, otg_bc_base + USB3PHY_CR_CTRL);
-
- usleep_range(100, 120);
-
- while (1) {
- reg = readl(otg_bc_base + USB3PHY_CR_STS);
- if ((reg & USB3OTG_PHY_CR_ACK) == 1)
- break;
- usleep_range(50, 60);
- if (i-- < 0) {
- usb_err("wait phy_cr_ack timeout!\n");
- break;
- }
- }
-
- /* clear ctrl reg */
- writel(0, otg_bc_base + USB3PHY_CR_CTRL);
-
- return (u16)USB3OTG_PHY_CR_DATA_OUT(reg);
-}
-
-static void phy_cr_write(void __iomem *otg_bc_base, u32 addr, u32 value)
-{
- u32 reg;
-
- phy_cr_set_addr(otg_bc_base, addr);
-
- reg = USB3OTG_PHY_CR_DATA_IN(value);
- writel(reg, otg_bc_base + USB3PHY_CR_CTRL);
-
- /* cap data */
- reg = readl(otg_bc_base + USB3PHY_CR_CTRL);
- reg |= USB3OTG_PHY_CR_CAP_DATA;
- writel(reg, otg_bc_base + USB3PHY_CR_CTRL);
-
- /* wait ack */
- phy_cr_wait_ack(otg_bc_base);
-
- /* clear ctrl reg */
- writel(0, otg_bc_base + USB3PHY_CR_CTRL);
-
- reg = USB3OTG_PHY_CR_WRITE;
- writel(reg, otg_bc_base + USB3PHY_CR_CTRL);
-
- /* wait ack */
- phy_cr_wait_ack(otg_bc_base);
-}
-
-void set_usb3_phy_cr_param(u32 addr, u32 value)
-{
- if (!hisi_dwc3_dev) {
- pr_err("hisi dwc3 device not ready!\n");
- return;
- }
-
- phy_cr_write(hisi_dwc3_dev->otg_bc_reg_base, addr, value);
-}
-EXPORT_SYMBOL_GPL(set_usb3_phy_cr_param);
-
-void read_usb3_phy_cr_param(u32 addr)
-{
- if (!hisi_dwc3_dev) {
- pr_err("hisi dwc3 device not ready!\n");
- return;
- }
-
- usb_dbg("read usb3 phy cr param 0x%x\n",
- phy_cr_read(hisi_dwc3_dev->otg_bc_reg_base, addr));
-}
-EXPORT_SYMBOL_GPL(read_usb3_phy_cr_param);
-
-void config_femtophy_param(struct hisi_dwc3_device *hisi_dwc)
-{
- u32 reg;
- void __iomem *otg_bc_base = hisi_dwc->otg_bc_reg_base;
-
- if (hisi_dwc->fpga_flag != 0)
- return;
-
- /* set high speed phy parameter */
- if (hisi_dwc->host_flag) {
- writel(hisi_dwc->eye_diagram_host_param,
- otg_bc_base + USBOTG3_CTRL4);
- usb_dbg("set hs phy param 0x%x for host\n",
- readl(otg_bc_base + USBOTG3_CTRL4));
- } else {
- writel(hisi_dwc->eye_diagram_param,
- otg_bc_base + USBOTG3_CTRL4);
- usb_dbg("set hs phy param 0x%x for device\n",
- readl(otg_bc_base + USBOTG3_CTRL4));
- }
-
- /* set usb3 phy cr config for usb3.0 */
-
- if (hisi_dwc->host_flag) {
- phy_cr_write(otg_bc_base, DWC3_PHY_RX_OVRD_IN_HI,
- hisi_dwc->usb3_phy_host_cr_param);
- } else {
- phy_cr_write(otg_bc_base, DWC3_PHY_RX_OVRD_IN_HI,
- hisi_dwc->usb3_phy_cr_param);
- }
-
- usb_dbg("set ss phy rx equalization 0x%x\n",
- phy_cr_read(otg_bc_base, DWC3_PHY_RX_OVRD_IN_HI));
-
- /* enable RX_SCOPE_LFPS_EN for usb3.0 */
- reg = phy_cr_read(otg_bc_base, DWC3_PHY_RX_SCOPE_VDCC);
- reg |= RX_SCOPE_LFPS_EN;
- phy_cr_write(otg_bc_base, DWC3_PHY_RX_SCOPE_VDCC, reg);
-
- usb_dbg("set ss RX_SCOPE_VDCC 0x%x\n",
- phy_cr_read(otg_bc_base, DWC3_PHY_RX_SCOPE_VDCC));
-
- reg = readl(otg_bc_base + USBOTG3_CTRL6);
- reg &= ~TX_VBOOST_LVL_MASK;
- reg |= TX_VBOOST_LVL(hisi_dwc->usb3_phy_tx_vboost_lvl);
- writel(reg, otg_bc_base + USBOTG3_CTRL6);
- usb_dbg("set ss phy tx vboost lvl 0x%x\n",
- readl(otg_bc_base + USBOTG3_CTRL6));
-}
-
-int hisi_charger_type_notifier_register(struct notifier_block *nb)
-{
- if (!hisi_dwc3_dev) {
- pr_err("hisi dwc3 device not ready!\n");
- return -EBUSY;
- }
- if (!nb)
- return -EINVAL;
- return atomic_notifier_chain_register(
- &hisi_dwc3_dev->charger_type_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(hisi_charger_type_notifier_register);
-
-int hisi_charger_type_notifier_unregister(struct notifier_block *nb)
-{
- if (!hisi_dwc3_dev) {
- pr_err("hisi dwc3 device not ready!\n");
- return -EBUSY;
- }
- if (!nb)
- return -EINVAL;
- return atomic_notifier_chain_unregister(
- &hisi_dwc3_dev->charger_type_notifier,
- nb);
-}
-EXPORT_SYMBOL_GPL(hisi_charger_type_notifier_unregister);
-
-/* BC1.2 Spec:
- * If a PD detects that D+ is greater than VDAT_REF, it knows that it is
- * attached to a DCP. It is then required to enable VDP_SRC or pull D+
- * to VDP_UP through RDP_UP
- */
-static void disable_vdp_src(struct hisi_dwc3_device *hisi_dwc3)
-{
- void __iomem *base = hisi_dwc3->otg_bc_reg_base;
- u32 reg;
-
- usb_dbg("diaable VDP_SRC\n");
-
- reg = readl(base + BC_CTRL2);
- reg &= ~(BC_CTRL2_BC_PHY_VDATARCENB | BC_CTRL2_BC_PHY_VDATDETENB);
- writel(reg, base + BC_CTRL2);
-
- reg = readl(base + BC_CTRL0);
- reg |= BC_CTRL0_BC_SUSPEND_N;
- writel(reg, base + BC_CTRL0);
-
- writel((readl(base + BC_CTRL1) & ~BC_CTRL1_BC_MODE), base + BC_CTRL1);
-}
-
-static void enable_vdp_src(struct hisi_dwc3_device *hisi_dwc3)
-{
- void __iomem *base = hisi_dwc3->otg_bc_reg_base;
- u32 reg;
-
- reg = readl(base + BC_CTRL2);
- reg &= ~BC_CTRL2_BC_PHY_CHRGSEL;
- reg |= (BC_CTRL2_BC_PHY_VDATARCENB | BC_CTRL2_BC_PHY_VDATDETENB);
- writel(reg, base + BC_CTRL2);
-}
-
-static enum hisi_charger_type detect_charger_type(struct hisi_dwc3_device
- *hisi_dwc3)
-{
- enum hisi_charger_type type = CHARGER_TYPE_NONE;
- void __iomem *base = hisi_dwc3->otg_bc_reg_base;
- u32 reg;
- unsigned long jiffies_expire;
- int i = 0;
-
- if (hisi_dwc3->fpga_flag) {
- usb_dbg("this is fpga platform, charger is SDP\n");
- return CHARGER_TYPE_SDP;
- }
-
- if (hisi_dwc3->fake_charger_type != CHARGER_TYPE_NONE) {
- usb_dbg("fake type: %d\n", hisi_dwc3->fake_charger_type);
- return hisi_dwc3->fake_charger_type;
- }
-
- writel(BC_CTRL1_BC_MODE, base + BC_CTRL1);
-
- /* phy suspend */
- reg = readl(base + BC_CTRL0);
- reg &= ~BC_CTRL0_BC_SUSPEND_N;
- writel(reg, base + BC_CTRL0);
-
- /* enable DCD */
- reg = readl(base + BC_CTRL2);
- reg |= BC_CTRL2_BC_PHY_DCDENB;
- writel(reg, base + BC_CTRL2);
-
- reg = readl(base + BC_CTRL0);
- reg |= BC_CTRL0_BC_DMPULLDOWN;
- writel(reg, base + BC_CTRL0);
-
- jiffies_expire = jiffies + msecs_to_jiffies(900);
- msleep(50);
- while (1) {
- reg = readl(base + BC_STS0);
- if ((reg & BC_STS0_BC_PHY_FSVPLUS) == 0) {
- i++;
- if (i >= 10)
- break;
- } else {
- i = 0;
- }
-
- msleep(20);
-
- if (time_after(jiffies, jiffies_expire)) {
- usb_dbg("DCD timeout!\n");
- type = CHARGER_TYPE_UNKNOWN;
- break;
- }
- }
-
- reg = readl(base + BC_CTRL0);
- reg &= ~BC_CTRL0_BC_DMPULLDOWN;
- writel(reg, base + BC_CTRL0);
-
- /* disable DCD */
- reg = readl(base + BC_CTRL2);
- reg &= ~BC_CTRL2_BC_PHY_DCDENB;
- writel(reg, base + BC_CTRL2);
-
- usb_dbg("DCD done\n");
-
- if (type == CHARGER_TYPE_NONE) {
- /* enable vdect */
- reg = readl(base + BC_CTRL2);
- reg &= ~BC_CTRL2_BC_PHY_CHRGSEL;
- reg |= (BC_CTRL2_BC_PHY_VDATARCENB |
- BC_CTRL2_BC_PHY_VDATDETENB);
- writel(reg, base + BC_CTRL2);
-
- msleep(20);
-
- /* we can detect sdp or cdp dcp */
- reg = readl(base + BC_STS0);
- if ((reg & BC_STS0_BC_PHY_CHGDET) == 0)
- type = CHARGER_TYPE_SDP;
-
- /* disable vdect */
- reg = readl(base + BC_CTRL2);
- reg &= ~(BC_CTRL2_BC_PHY_VDATARCENB |
- BC_CTRL2_BC_PHY_VDATDETENB);
- writel(reg, base + BC_CTRL2);
- }
-
- usb_dbg("Primary Detection done\n");
-
- if (type == CHARGER_TYPE_NONE) {
- /* enable vdect */
- reg = readl(base + BC_CTRL2);
- reg |= (BC_CTRL2_BC_PHY_VDATARCENB | BC_CTRL2_BC_PHY_VDATDETENB
- | BC_CTRL2_BC_PHY_CHRGSEL);
- writel(reg, base + BC_CTRL2);
-
- msleep(20);
-
- /* we can detect sdp or cdp dcp */
- reg = readl(base + BC_STS0);
- if ((reg & BC_STS0_BC_PHY_CHGDET) == 0)
- type = CHARGER_TYPE_CDP;
- else
- type = CHARGER_TYPE_DCP;
-
- /* disable vdect */
- reg = readl(base + BC_CTRL2);
- reg &= ~(BC_CTRL2_BC_PHY_VDATARCENB | BC_CTRL2_BC_PHY_VDATDETENB
- | BC_CTRL2_BC_PHY_CHRGSEL);
- writel(reg, base + BC_CTRL2);
- }
-
- usb_dbg("Secondary Detection done\n");
-
- /* If a PD detects that D+ is greater than VDAT_REF, it knows that it is
- * attached to a DCP. It is then required to enable VDP_SRC or pull D+
- * to VDP_UP through RDP_UP
- */
- if (type == CHARGER_TYPE_DCP) {
- usb_dbg("charger is DCP, enable VDP_SRC\n");
- enable_vdp_src(hisi_dwc3);
- } else {
- /* bc_suspend = 1, nomal mode */
- reg = readl(base + BC_CTRL0);
- reg |= BC_CTRL0_BC_SUSPEND_N;
- writel(reg, base + BC_CTRL0);
-
- msleep(20);
-
- /* disable BC */
- writel((readl(base + BC_CTRL1) & ~BC_CTRL1_BC_MODE),
- base + BC_CTRL1);
- }
-
- usb_dbg("type: %d\n", type);
-
- return type;
-}
-
-enum hisi_charger_type hisi_get_charger_type(void)
-{
- if (!hisi_dwc3_dev) {
- pr_err("[%s]hisi_dwc3 not yet probed!\n", __func__);
- return CHARGER_TYPE_NONE;
- }
-
- pr_info("[%s]type: %d\n", __func__, hisi_dwc3_dev->charger_type);
- return hisi_dwc3_dev->charger_type;
-}
-EXPORT_SYMBOL_GPL(hisi_get_charger_type);
-
-static void notify_charger_type(struct hisi_dwc3_device *hisi_dwc3)
-{
- atomic_notifier_call_chain(&hisi_dwc3->charger_type_notifier,
- hisi_dwc3->charger_type, hisi_dwc3);
-}
-
-static void set_vbus_power(struct hisi_dwc3_device *hisi_dwc3,
- unsigned int is_on)
-{
- enum hisi_charger_type new;
-
- if (is_on == 0)
- new = CHARGER_TYPE_NONE;
- else
- new = PLEASE_PROVIDE_POWER;
- if (hisi_dwc3->charger_type != new) {
- usb_dbg("set port power %d\n", is_on);
- hisi_dwc3->charger_type = new;
- notify_charger_type(hisi_dwc3);
- }
-}
-
-static void hisi_dwc3_wake_lock(struct hisi_dwc3_device *hisi_dwc3)
-{
- if (!(hisi_dwc3->ws.active)) {
- usb_dbg("usb otg wake lock\n");
- __pm_stay_awake(&hisi_dwc3->ws);
- }
-}
-
-static void hisi_dwc3_wake_unlock(struct hisi_dwc3_device *hisi_dwc3)
-{
- if (hisi_dwc3->ws.active) {
- usb_dbg("usb otg wake unlock\n");
- __pm_relax(&hisi_dwc3->ws);
- }
-}
-
-static inline bool enumerate_allowed(struct hisi_dwc3_device *hisi_dwc)
-{
- /* do not start peripheral if real charger connected */
- return ((hisi_dwc->charger_type == CHARGER_TYPE_SDP) ||
- (hisi_dwc->charger_type == CHARGER_TYPE_CDP) ||
- (hisi_dwc->charger_type == CHARGER_TYPE_UNKNOWN));
-}
-
-static inline bool sleep_allowed(struct hisi_dwc3_device *hisi_dwc)
-{
- return ((hisi_dwc->charger_type == CHARGER_TYPE_DCP) ||
- (hisi_dwc->charger_type == CHARGER_TYPE_UNKNOWN));
-}
-
-/*
- * create event queue
- * event_queue: event queue handle
- * count: set the queue max node
- */
-int event_queue_creat(struct hiusb_event_queue *event_queue, unsigned int count)
-{
- if (!event_queue) {
- pr_err(" %s bad argument (0x%p)\n",
- __func__, event_queue);
- return -EINVAL;
- }
-
- count = (count >= MAX_EVENT_COUNT ? MAX_EVENT_COUNT : count);
- event_queue->max_event = count;
- event_queue->num_event = (count >= EVENT_QUEUE_UNIT ?
- EVENT_QUEUE_UNIT : count);
-
- event_queue->event = kzalloc(
- (event_queue->num_event *
- sizeof(enum otg_dev_event_type)), GFP_KERNEL);
- if (!event_queue->event) {
- pr_err(" %s :Can't alloc space:%d!\n",
- __func__, event_queue->num_event);
- return -ENOMEM;
- }
-
- event_queue->enpos = 0;
- event_queue->depos = 0;
- event_queue->overlay = 0;
- event_queue->overlay_index = 0;
-
- return 0;
-}
-
-void event_queue_destroy(struct hiusb_event_queue *event_queue)
-{
- if (!event_queue)
- return;
-
- kfree(event_queue->event);
- event_queue->event = NULL;
- event_queue->enpos = 0;
- event_queue->depos = 0;
- event_queue->num_event = 0;
- event_queue->max_event = 0;
- event_queue->overlay = 0;
- event_queue->overlay_index = 0;
-}
-
-/*
- * check if the queue is full
- * return true means full, false is not.
- */
-int event_queue_isfull(struct hiusb_event_queue *event_queue)
-{
- if (!event_queue)
- return -EINVAL;
-
- return (((event_queue->enpos + 1) % event_queue->num_event) ==
- (event_queue->depos));
-}
-
-/*
- * check if the queue is full
- * return true means empty, false or not.
- */
-int event_queue_isempty(struct hiusb_event_queue *event_queue)
-{
- if (!event_queue)
- return -EINVAL;
-
- return (event_queue->enpos == event_queue->depos);
-}
-
-static inline void event_queue_set_overlay(
- struct hiusb_event_queue *event_queue)
-{
- if (event_queue->overlay)
- return;
- event_queue->overlay = 1;
- event_queue->overlay_index = event_queue->enpos;
-}
-
-static inline void event_queue_clear_overlay(
- struct hiusb_event_queue *event_queue)
-{
- event_queue->overlay = 0;
- event_queue->overlay_index = 0;
-}
-
-/*
- * put the new event en queue
- * if the event_queue is full, return -ENOSPC
- */
-int event_enqueue(struct hiusb_event_queue *event_queue,
- enum otg_dev_event_type event)
-{
- /* no need verify argument, isfull will check it */
- if (event_queue_isfull(event_queue)) {
- pr_err("event queue full!\n");
- return -ENOSPC;
- }
-
- if (event_queue->overlay) {
- if (event_queue->overlay_index == event_queue->enpos) {
- event_queue->enpos = ((event_queue->enpos + 1) %
- event_queue->num_event);
- }
-
- if (event_queue_isempty(event_queue)) {
- pr_err("overlay and queue isempty? just enqueue!\n");
- event_queue->overlay_index = (
- (event_queue->overlay_index + 1) %
- event_queue->num_event);
- event_queue->enpos = ((event_queue->enpos + 1) %
- event_queue->num_event);
- event_queue->overlay = 0;
- }
-
- event_queue->event[event_queue->overlay_index] = event;
- } else {
- event_queue->event[event_queue->enpos] = event;
- event_queue->enpos = ((event_queue->enpos + 1) %
- event_queue->num_event);
- }
-
- return 0;
-}
-
-/*
- * get event from event_queue
- * this function never return fail
- * if the event_queue is empty, return NONE_EVENT
- */
-enum otg_dev_event_type event_dequeue(struct hiusb_event_queue *event_queue)
-{
- enum otg_dev_event_type event;
-
- /* no need verify argument, isempty will check it */
- if (event_queue_isempty(event_queue))
- return NONE_EVENT;
-
- event = event_queue->event[event_queue->depos];
- event_queue->depos = ((event_queue->depos + 1) %
- event_queue->num_event);
-
- return event;
-}
-
-static void handle_event(struct hisi_dwc3_device *hisi_dwc,
- enum otg_dev_event_type event)
-{
- int ret = 0;
-
- usb_err("[handle_event] type: %d\n", event);
- switch (event) {
- case CHARGER_CONNECT_EVENT:
- if (hisi_dwc->state == USB_STATE_DEVICE) {
- usb_dbg("Already in device mode, do nothing\n");
- } else if (hisi_dwc->state == USB_STATE_OFF) {
- hisi_dwc->host_flag = 0;
-
- /* due to detect charger type, must resume hisi_dwc */
- ret = pm_runtime_get_sync(&hisi_dwc->pdev->dev);
- if (ret < 0) {
- usb_err("resume hisi_dwc failed (ret %d)\n",
- ret);
- return;
- }
-
- /* detect charger type */
- hisi_dwc->charger_type = detect_charger_type(hisi_dwc);
- notify_charger_type(hisi_dwc);
-
- /* In some cases, DCP is detected as SDP wrongly.
- * To avoid this, start bc_again delay work to
- * detect charger type once more.
- * If later the enum process is executed,
- * then it's a real SDP, so
- * the work will be canceled.
- */
- if (hisi_dwc->bc_again_flag &&
- (hisi_dwc->charger_type == CHARGER_TYPE_SDP)) {
- ret = queue_delayed_work(
- system_power_efficient_wq,
- &hisi_dwc->bc_again_work,
- msecs_to_jiffies(BC_AGAIN_DELAY_TIME));
- usb_dbg("schedule ret:%d, run bc_again_work %dms later\n",
- ret, BC_AGAIN_DELAY_TIME);
- }
-
- /* do not start peripheral if real charger connected */
- if (enumerate_allowed(hisi_dwc)) {
- if (hisi_dwc->fpga_usb_mode_gpio > 0) {
- gpio_direction_output(
- hisi_dwc->fpga_usb_mode_gpio,
- 0);
- usb_dbg("switch to device mode\n");
- }
-
- /* start peripheral */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_VBUS_SET);
- if (ret) {
- pm_runtime_put(&hisi_dwc->pdev->dev);
- hisi_dwc3_wake_unlock(hisi_dwc);
- usb_err("start peripheral error\n");
- return;
- }
- } else {
- usb_dbg("a real charger connected\n");
- }
-
- hisi_dwc->state = USB_STATE_DEVICE;
-
- if (sleep_allowed(hisi_dwc))
- hisi_dwc3_wake_unlock(hisi_dwc);
- else
- hisi_dwc3_wake_lock(hisi_dwc);
-
- usb_dbg("hisi usb status: OFF -> DEVICE\n");
- } else if (hisi_dwc->state == USB_STATE_HOST) {
- usb_dbg("Charger connect interrupt in HOST mode\n");
- }
-
- break;
-
- case CHARGER_DISCONNECT_EVENT:
- hisi_dwc->need_disable_vdp = 0;
-
- if (hisi_dwc->state == USB_STATE_OFF) {
- usb_dbg("Already in off mode, do nothing\n");
- } else if (hisi_dwc->state == USB_STATE_DEVICE) {
- if (hisi_dwc->bc_again_flag) {
- ret = cancel_delayed_work_sync(
- &hisi_dwc->bc_again_work);
- usb_dbg("cancel bc_again_work sync:%d\n", ret);
- }
-
- /* peripheral not started, if real charger connected */
- if (enumerate_allowed(hisi_dwc)) {
- /* stop peripheral */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_VBUS_CLEAR);
- if (ret) {
- usb_err("stop peripheral error\n");
- return;
- }
- } else {
- usb_dbg("connected is a real charger\n");
- disable_vdp_src(hisi_dwc);
- }
-
- /* usb cable disconnect, notify no charger */
- hisi_dwc->charger_type = CHARGER_TYPE_NONE;
- notify_charger_type(hisi_dwc);
-
- hisi_dwc->state = USB_STATE_OFF;
- hisi_dwc3_wake_unlock(hisi_dwc);
- pm_runtime_put(&hisi_dwc->pdev->dev);
-
- usb_dbg("hisi usb status: DEVICE -> OFF\n");
- } else if (hisi_dwc->state == USB_STATE_HOST) {
- usb_dbg("Charger disconnect interrupt in HOST mode\n");
- }
-
- break;
-
- case ID_FALL_EVENT:
- if (hisi_dwc->state == USB_STATE_OFF) {
- set_vbus_power(hisi_dwc, 1);
-
- hisi_dwc->host_flag = 1;
-
- if (hisi_dwc->fpga_usb_mode_gpio > 0) {
- gpio_direction_output(
- hisi_dwc->fpga_usb_mode_gpio,
- 1);
- usb_dbg("switch to host mode\n");
- }
-
- /* start host */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_ID_CLEAR);
- if (ret) {
- usb_err("start host error\n");
- set_vbus_power(hisi_dwc, 0);
- return;
- }
-
- hisi_dwc->state = USB_STATE_HOST;
- hisi_dwc3_wake_lock(hisi_dwc);
-
- usb_dbg("hisi usb_status: OFF -> HOST\n");
- } else if (hisi_dwc->state == USB_STATE_DEVICE) {
- usb_dbg("id fall interrupt in DEVICE mode\n");
- } else if (hisi_dwc->state == USB_STATE_HOST) {
- usb_dbg("Already in host mode, do nothing\n");
- }
- break;
- case ID_RISE_EVENT:
- if (hisi_dwc->state == USB_STATE_HOST) {
- set_vbus_power(hisi_dwc, 0);
-
- /* stop host */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_ID_SET);
- if (ret) {
- usb_err("stop host error\n");
- return;
- }
-
- hisi_dwc->state = USB_STATE_OFF;
- hisi_dwc3_wake_unlock(hisi_dwc);
-
- usb_dbg("hiusb_status: HOST -> OFF\n");
- } else if (hisi_dwc->state == USB_STATE_DEVICE) {
- usb_dbg("id rise interrupt in DEVICE mode\n");
- } else if (hisi_dwc->state == USB_STATE_OFF) {
- usb_dbg("Already in host mode, do nothing\n");
- }
-
- break;
- default:
- usb_dbg("illegal event type!\n");
- break;
- }
-}
-
-static void event_work(struct work_struct *work)
-{
- unsigned long flags;
- enum otg_dev_event_type event;
- struct hisi_dwc3_device *hisi_dwc = container_of(work,
- struct hisi_dwc3_device, event_work);
-
- mutex_lock(&hisi_dwc->lock);
-
- usb_dbg("+\n");
-
- while (!event_queue_isempty(&hisi_dwc->event_queue)) {
- spin_lock_irqsave(&hisi_dwc->event_lock, flags);
- event = event_dequeue(&hisi_dwc->event_queue);
- spin_unlock_irqrestore(&hisi_dwc->event_lock, flags);
-
- handle_event(hisi_dwc, event);
- }
-
- event_queue_clear_overlay(&hisi_dwc->event_queue);
-
- usb_dbg("-\n");
- mutex_unlock(&hisi_dwc->lock);
-}
-
-static int event_check(enum otg_dev_event_type last_event,
- enum otg_dev_event_type new_event)
-{
- int ret = 0;
-
- if (last_event == NONE_EVENT)
- return 1;
-
- switch (new_event) {
- case CHARGER_CONNECT_EVENT:
- if ((last_event == CHARGER_DISCONNECT_EVENT) ||
- (last_event == ID_RISE_EVENT))
- ret = 1;
- break;
- case CHARGER_DISCONNECT_EVENT:
- if (last_event == CHARGER_CONNECT_EVENT)
- ret = 1;
- break;
- case ID_FALL_EVENT:
- if ((last_event == CHARGER_DISCONNECT_EVENT) ||
- (last_event == ID_RISE_EVENT))
- ret = 1;
- break;
- case ID_RISE_EVENT:
- if (last_event == ID_FALL_EVENT)
- ret = 1;
- break;
- default:
- break;
- }
- return ret;
-}
-
-int hisi_usb_otg_event(enum otg_dev_event_type event)
-{
- int ret = 0;
-#ifdef CONFIG_USB_DWC3_OTG
- unsigned long flags;
- struct hisi_dwc3_device *hisi_dwc3 = hisi_dwc3_dev;
-#endif
- usb_err("%s in:%d\n", __func__, event);
-#ifdef CONFIG_USB_DWC3_OTG
- usb_err("%s in otg:%d\n", __func__, event);
-
- if (!hisi_dwc3) {
- usb_dbg(" %s error:%d\n", __func__, event);
- return -EBUSY;
- }
-
- if (hisi_dwc3->eventmask) {
- usb_dbg("eventmask enabled, mask all events.\n");
- return ret;
- }
-
- spin_lock_irqsave(&hisi_dwc3->event_lock, flags);
-
- if (event_check(hisi_dwc3->event, event)) {
- usb_dbg("event: %d\n", event);
- hisi_dwc3->event = event;
-
- if ((event == CHARGER_CONNECT_EVENT) ||
- (event == CHARGER_DISCONNECT_EVENT))
- hisi_dwc3_wake_lock(hisi_dwc3);
-
- if (!event_enqueue(&hisi_dwc3->event_queue, event)) {
- ret = queue_work(system_power_efficient_wq,
- &hisi_dwc3->event_work);
- if (!ret)
- usb_err("schedule event_work wait:%d]\n",
- event);
- } else {
- usb_err("%s can't enqueue event:%d\n",
- __func__, event);
- }
-
- if ((event == ID_RISE_EVENT) ||
- (event == CHARGER_DISCONNECT_EVENT))
- event_queue_set_overlay(&hisi_dwc3->event_queue);
- }
- spin_unlock_irqrestore(&hisi_dwc3->event_lock, flags);
-#endif
- return ret;
-}
-EXPORT_SYMBOL_GPL(hisi_usb_otg_event);
-
-static void bc_again(struct hisi_dwc3_device *hisi_dwc)
-{
- int ret;
-
- /*
- * STEP 1
- */
- /* stop peripheral which is started when detected as SDP before */
- if (enumerate_allowed(hisi_dwc)) {
- ret = dwc3_otg_work(dwc_otg_handler, DWC3_OTG_EVT_VBUS_CLEAR);
- if (ret) {
- usb_err("stop peripheral error\n");
- return;
- }
- }
-
- /*
- * STEP 2
- */
- hisi_dwc->charger_type = detect_charger_type(hisi_dwc);
- notify_charger_type(hisi_dwc);
-
- /*
- * STEP 3
- */
- /* must recheck enumerate_allowed, because charger_type maybe changed,
- * and enumerate_allowed according to charger_type
- */
- if (enumerate_allowed(hisi_dwc)) {
- /* start peripheral */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_VBUS_SET);
- if (ret) {
- pm_runtime_put(&hisi_dwc->pdev->dev);
- hisi_dwc3_wake_unlock(hisi_dwc);
- usb_err("start peripheral error\n");
- return;
- }
- } else {
- usb_dbg("a real charger connected\n");
- }
-}
-
-void hisi_usb_otg_bc_again(void)
-{
- struct hisi_dwc3_device *hisi_dwc = hisi_dwc3_dev;
-
- usb_dbg("+\n");
-
- if (!hisi_dwc) {
- usb_err("No usb module, can't call bc again api\n");
- return;
- }
-
- mutex_lock(&hisi_dwc->lock);
-
- /* we are here because it's detected as SDP before */
- if (hisi_dwc->charger_type == CHARGER_TYPE_UNKNOWN) {
- usb_dbg("charger_type is UNKNOWN, start bc_again_work\n");
- bc_again(hisi_dwc);
- }
-
- mutex_unlock(&hisi_dwc->lock);
- usb_dbg("-\n");
-}
-EXPORT_SYMBOL_GPL(hisi_usb_otg_bc_again);
-
-static void bc_again_work(struct work_struct *work)
-{
- struct hisi_dwc3_device *hisi_dwc = container_of(work,
- struct hisi_dwc3_device, bc_again_work.work);
-
- usb_dbg("+\n");
- mutex_lock(&hisi_dwc->lock);
-
- /* we are here because it's detected as SDP before */
- if (hisi_dwc->charger_type == CHARGER_TYPE_SDP) {
- usb_dbg("charger_type is SDP, start %s\n", __func__);
- bc_again(hisi_dwc);
- }
-
- mutex_unlock(&hisi_dwc->lock);
- usb_dbg("-\n");
-}
-
-static int conndone_notifier_fn(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- int ret;
- struct hisi_dwc3_device *hisi_dwc = container_of(nb,
- struct hisi_dwc3_device, conndone_nb);
-
- ret = cancel_delayed_work(&hisi_dwc->bc_again_work);
- usb_dbg("cancel bc_again_work:%d\n", ret);
-
- return 0;
-}
-
-/**
- * get_usb_state() - get current USB cable state.
- * @hisi_dwc: the instance pointer of struct hisi_dwc3_device
- *
- * return current USB cable state according to VBUS status and ID status.
- */
-static enum hisi_usb_state get_usb_state(struct hisi_dwc3_device *hisi_dwc)
-{
- if (hisi_dwc->fpga_flag) {
- usb_dbg("this is fpga platform, usb is device mode\n");
- return USB_STATE_DEVICE;
- }
-
- if (dwc3_otg_id_value(dwc_otg_handler) == 0)
- return USB_STATE_HOST;
- else
- return USB_STATE_OFF;
-}
-
-static void get_phy_param(struct hisi_dwc3_device *hisi_dwc3)
-{
- struct device *dev = &hisi_dwc3->pdev->dev;
-
- /* hs phy param for device mode */
- if (of_property_read_u32(dev->of_node, "eye_diagram_param",
- &hisi_dwc3->eye_diagram_param)) {
- usb_dbg("get eye diagram param form dt failed, use default value\n");
- hisi_dwc3->eye_diagram_param = 0x1c466e3;
- }
- usb_dbg("eye diagram param: 0x%x\n", hisi_dwc3->eye_diagram_param);
-
- /* hs phy param for host mode */
- if (of_property_read_u32(dev->of_node, "eye_diagram_host_param",
- &hisi_dwc3->eye_diagram_host_param)) {
- usb_dbg("get eye diagram host param form dt failed, use default value\n");
- hisi_dwc3->eye_diagram_host_param = 0x1c466e3;
- }
- usb_dbg("eye diagram host param: 0x%x\n",
- hisi_dwc3->eye_diagram_host_param);
-
- /* ss phy Rx Equalization */
- if (of_property_read_u32(dev->of_node, "usb3_phy_cr_param",
- &hisi_dwc3->usb3_phy_cr_param)) {
- usb_dbg("get usb3_phy_cr_param form dt failed, use default value\n");
- hisi_dwc3->usb3_phy_cr_param = (1 << 11) | (3 << 8) | (1 << 7);
- }
-
- /* ss phy Rx Equalization for host mode */
- if (of_property_read_u32(dev->of_node, "usb3_phy_host_cr_param",
- &hisi_dwc3->usb3_phy_host_cr_param)) {
- usb_dbg("get usb3_phy_host_cr_param form dt failed, use default value\n");
- hisi_dwc3->usb3_phy_host_cr_param =
- (1 << 11) | (1 << 8) | (1 << 7);
- }
-
- usb_dbg("usb3_phy_cr_param: 0x%x\n", hisi_dwc3->usb3_phy_cr_param);
- usb_dbg("usb3_phy_host_cr_param: 0x%x\n",
- hisi_dwc3->usb3_phy_host_cr_param);
-
- /* tx_vboost_lvl */
- if (of_property_read_u32(dev->of_node, "usb3_phy_tx_vboost_lvl",
- &hisi_dwc3->usb3_phy_tx_vboost_lvl)) {
- usb_dbg("get usb3_phy_tx_vboost_lvl form dt failed, use default value\n");
- hisi_dwc3->usb3_phy_tx_vboost_lvl = 5;
- }
- usb_dbg("usb3_phy_tx_vboost_lvl: %d\n",
- hisi_dwc3->usb3_phy_tx_vboost_lvl);
-}
-
-/**
- * get_resource() - prepare resources
- * @hisi_dwc3: the instance pointer of struct hisi_dwc3_device
- *
- * 1. get registers base address and map registers region.
- * 2. get regulator handler.
- */
-static int get_resource(struct hisi_dwc3_device *hisi_dwc3)
-{
- struct device *dev = &hisi_dwc3->pdev->dev;
- struct resource *res;
- struct device_node *np;
-
- /*
- * map PERI CRG region
- */
- np = of_find_compatible_node(NULL, NULL, "hisilicon,hi3660-crgctrl");
- if (!np) {
- dev_err(dev, "get peri cfg node failed!\n");
- return -EINVAL;
- }
- hisi_dwc3->pericfg_reg_base = of_iomap(np, 0);
- if (!hisi_dwc3->pericfg_reg_base) {
- dev_err(dev, "iomap pericfg_reg_base failed!\n");
- return -EINVAL;
- }
-
- /*
- * map PCTRL region
- */
- np = of_find_compatible_node(NULL, NULL, "hisilicon,hi3660-pctrl");
- if (!np) {
- dev_err(dev, "get pctrl node failed!\n");
- return -EINVAL;
- }
- hisi_dwc3->pctrl_reg_base = of_iomap(np, 0);
- if (!hisi_dwc3->pctrl_reg_base) {
- dev_err(dev, "iomap pctrl_reg_base failed!\n");
- return -EINVAL;
- }
-
- /*
- * map SCTRL region
- */
- np = of_find_compatible_node(NULL, NULL, "hisilicon,hi3660-sctrl");
- if (!np) {
- dev_err(dev, "get sysctrl node failed!\n");
- return -EINVAL;
- }
- hisi_dwc3->sctrl_reg_base = of_iomap(np, 0);
- if (!hisi_dwc3->sctrl_reg_base) {
- dev_err(dev, "iomap sctrl_reg_base failed!\n");
- return -EINVAL;
- }
-
- /*
- * map PMCTRL region
- */
- np = of_find_compatible_node(NULL, NULL, "hisilicon,hi3660-pmctrl");
- if (!np) {
- dev_err(dev, "get pmctrl node failed!\n");
- return -EINVAL;
- }
-
- /*
- * map OTG BC region
- */
- res = platform_get_resource(hisi_dwc3->pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing memory base resource\n");
- return -EINVAL;
- }
-
- hisi_dwc3->otg_bc_reg_base = devm_ioremap_nocache(
- dev, res->start, resource_size(res));
- if (IS_ERR_OR_NULL(hisi_dwc3->otg_bc_reg_base)) {
- dev_err(dev, "ioremap res 0 failed\n");
- return -ENOMEM;
- }
-
- get_phy_param(hisi_dwc3);
-
- /* get abb clk handler */
- hisi_dwc3->clk = devm_clk_get(&hisi_dwc3->pdev->dev, "clk_usb3phy_ref");
- if (IS_ERR_OR_NULL(hisi_dwc3->clk)) {
- dev_err(dev, "get usb3phy ref clk failed\n");
- return -EINVAL;
- }
-
- /* get h clk handler */
- hisi_dwc3->gt_aclk_usb3otg = devm_clk_get(
- &hisi_dwc3->pdev->dev, "aclk_usb3otg");
- if (IS_ERR_OR_NULL(hisi_dwc3->gt_aclk_usb3otg)) {
- dev_err(dev, "get aclk_usb3otg failed\n");
- return -EINVAL;
- }
-
- /* judge fpga platform or not, from dts */
- if (of_property_read_u32(dev->of_node, "fpga_flag",
- &hisi_dwc3->fpga_flag)) {
- hisi_dwc3->fpga_flag = 0;
- }
- usb_dbg("this is %s platform (fpga flag %d)\n",
- hisi_dwc3->fpga_flag ? "fpga" : "asic", hisi_dwc3->fpga_flag);
-
- hisi_dwc3->fpga_usb_mode_gpio = -1;
-
- if (of_property_read_u32(dev->of_node, "bc_again_flag",
- &hisi_dwc3->bc_again_flag)) {
- hisi_dwc3->bc_again_flag = 0;
- }
-
- return 0;
-}
-
-static int hisi_dwc3_phy_init(struct hisi_dwc3_device *hisi_dwc)
-{
- return hisi_dwc->phy_ops->init(hisi_dwc);
-}
-
-static int hisi_dwc3_phy_shutdown(struct hisi_dwc3_device *hisi_dwc)
-{
- return hisi_dwc->phy_ops->shutdown(hisi_dwc);
-}
-
-int hisi_dwc3_probe(struct platform_device *pdev,
- struct usb3_phy_ops *phy_ops)
-{
- int ret;
- struct hisi_dwc3_device *hisi_dwc;
- struct device *dev = &pdev->dev;
- struct device_node *node = pdev->dev.of_node;
- enum hisi_usb_state init_state;
-
- usb_dbg("+\n");
-
- if (!phy_ops) {
- usb_err("phy_ops is NULL\n");
- return -EINVAL;
- }
-
- hisi_dwc = devm_kzalloc(dev, sizeof(*hisi_dwc), GFP_KERNEL);
- if (!hisi_dwc)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, hisi_dwc);
- hisi_dwc->pdev = pdev;
- hisi_dwc->phy_ops = phy_ops;
-
- hisi_dwc3_dev = hisi_dwc;
-
- /*
- * set hisi dwc3 dma mask, it should be 0xffffffff, because the ahb
- * master of usb can only support 32bit width address.
- */
- if (!dev->dma_mask)
- dev->dma_mask = &dev->coherent_dma_mask;
- if (!dev->coherent_dma_mask)
- dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
- /*
- * get resources from dts.
- */
- ret = get_resource(hisi_dwc);
- if (ret) {
- dev_err(&pdev->dev, "get resource failed!\n");
- return ret;
- }
-
- if (hisi_dwc->fpga_usb_mode_gpio > 0) {
- ret = gpio_request(hisi_dwc->fpga_usb_mode_gpio, NULL);
- if (ret) {
- /* request gpio failure! */
- usb_err("request gpio %d failed, ret=[%d]\n",
- hisi_dwc->fpga_usb_mode_gpio, ret);
- }
- }
-
- /* create sysfs files. */
- ret = create_attr_file(dev);
- if (ret) {
- dev_err(&pdev->dev, "create_attr_file failed!\n");
- return ret;
- }
-
- /* initialize */
- hisi_dwc->charger_type = CHARGER_TYPE_SDP;
- hisi_dwc->fake_charger_type = CHARGER_TYPE_NONE;
- hisi_dwc->event = NONE_EVENT;
- hisi_dwc->host_flag = 0;
- hisi_dwc->eventmask = 0;
- spin_lock_init(&hisi_dwc->event_lock);
- INIT_WORK(&hisi_dwc->event_work, event_work);
- mutex_init(&hisi_dwc->lock);
- wakeup_source_init(&hisi_dwc->ws, "usb_wake_lock");
- ATOMIC_INIT_NOTIFIER_HEAD(&hisi_dwc->charger_type_notifier);
- event_queue_creat(&hisi_dwc->event_queue, MAX_EVENT_COUNT);
- hisi_dwc->disable_vdp_src = disable_vdp_src;
- hisi_dwc->need_disable_vdp = 0;
-
- /* power on */
- hisi_dwc->is_regu_on = 0;
- ret = hisi_dwc3_phy_init(hisi_dwc);
- if (ret) {
- dev_err(&pdev->dev, "%s: hisi_dwc3_phy_init failed!\n",
- __func__);
- remove_attr_file(dev);
- return ret;
- }
-
- if (hisi_dwc->bc_again_flag) {
- INIT_DELAYED_WORK(&hisi_dwc->bc_again_work, bc_again_work);
- hisi_dwc->conndone_nb.notifier_call = conndone_notifier_fn;
- ret = dwc3_conndone_notifier_register(&hisi_dwc->conndone_nb);
- if (ret)
- usb_err("dwc3_conndone_notifier_register failed\n");
- }
-
- if (hisi_dwc->charger_type == CHARGER_TYPE_CDP) {
- usb_dbg("it needs enable VDP_SRC while detect CDP!\n");
- hisi_dwc->need_disable_vdp = 1;
- enable_vdp_src(hisi_dwc);
- }
-
- /*
- * enable runtime pm.
- */
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_runtime_get_sync(dev);
- pm_runtime_forbid(dev);
-
- /*
- * probe child deivces
- */
- ret = of_platform_populate(node, NULL, NULL, dev);
- if (ret) {
- pr_err("%s: register dwc3 failed!\n", __func__);
- goto err1;
- }
-
-#ifdef CONFIG_USB_DWC3_OTG
- /* default device state */
- hisi_dwc->state = USB_STATE_DEVICE;
-
- if (sleep_allowed(hisi_dwc))
- hisi_dwc3_wake_unlock(hisi_dwc);
- else
- hisi_dwc3_wake_lock(hisi_dwc);
-
- if (!enumerate_allowed(hisi_dwc)) {
- /* stop peripheral */
- ret = dwc3_otg_work(dwc_otg_handler, DWC3_OTG_EVT_VBUS_CLEAR);
- if (ret)
- usb_err("stop peripheral error\n");
- }
-
- /* balance the put operation when disconnect */
- pm_runtime_get(dev);
-
- hisi_dwc->event = CHARGER_CONNECT_EVENT;
- init_state = get_usb_state(hisi_dwc);
- if (init_state == USB_STATE_OFF) {
- usb_dbg("init state: OFF\n");
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- } else if (init_state == USB_STATE_HOST) {
- usb_dbg("init state: HOST\n");
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- msleep(500);
- hisi_usb_otg_event(ID_FALL_EVENT);
- }
-#endif
-
- pm_runtime_put_sync(dev);
- pm_runtime_allow(dev);
-
- usb_dbg("-\n");
-
- return 0;
-
-err1:
- pm_runtime_put_sync(dev);
- pm_runtime_disable(dev);
- remove_attr_file(dev);
-
- return ret;
-}
-
-static int hisi_dwc3_remove_child(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
- return 0;
-}
-
-int hisi_dwc3_remove(struct platform_device *pdev)
-{
- struct hisi_dwc3_device *hisi_dwc3 = platform_get_drvdata(pdev);
- int ret;
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return -EBUSY;
- }
-
- device_for_each_child(&pdev->dev, NULL, hisi_dwc3_remove_child);
- pm_runtime_disable(&pdev->dev);
-
- if (hisi_dwc3->bc_again_flag) {
- dwc3_conndone_notifier_unregister(&hisi_dwc3->conndone_nb);
- hisi_dwc3->conndone_nb.notifier_call = NULL;
- }
-
- ret = hisi_dwc3_phy_shutdown(hisi_dwc3);
- if (ret)
- usb_err("hisi_dwc3_phy_shutdown error\n");
- hisi_dwc3->phy_ops = NULL;
-
- event_queue_destroy(&hisi_dwc3->event_queue);
-
- remove_attr_file(&pdev->dev);
- return 0;
-}
-
-#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
-static int hisi_dwc3_prepare(struct device *dev)
-{
- struct hisi_dwc3_device *hisi_dwc = platform_get_drvdata(
- to_platform_device(dev));
- int ret = 0;
-
- if (!hisi_dwc)
- return -ENODEV;
-
- mutex_lock(&hisi_dwc->lock);
-
- switch (hisi_dwc->state) {
- case USB_STATE_OFF:
- pr_info("%s: off state.\n", __func__);
- break;
- case USB_STATE_DEVICE:
- pr_info("%s: device state.\n", __func__);
-
- if (enumerate_allowed(hisi_dwc)) {
- /* stop peripheral */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_VBUS_CLEAR);
- if (ret) {
- usb_err("stop peripheral error\n");
- goto error;
- }
- } else {
- usb_dbg("connected is a real charger\n");
- disable_vdp_src(hisi_dwc);
- }
-
- break;
- case USB_STATE_HOST:
- usb_err("%s: host mode, should not go to sleep!\n", __func__);
- ret = -EFAULT;
- goto error;
- default:
- pr_err("%s: ilegal state!\n", __func__);
- ret = -EFAULT;
- goto error;
- }
-
- return ret;
-error:
- mutex_unlock(&hisi_dwc->lock);
- return ret;
-}
-
-static void hisi_dwc3_complete(struct device *dev)
-{
- struct hisi_dwc3_device *hisi_dwc = platform_get_drvdata(
- to_platform_device(dev));
- int ret = 0;
-
- if (!hisi_dwc) {
- usb_err("hisi_dwc NULL !\n");
- return;
- }
-
- switch (hisi_dwc->state) {
- case USB_STATE_OFF:
- usb_dbg("%s: off state.\n", __func__);
- break;
- case USB_STATE_DEVICE:
- usb_dbg("%s: device state.\n", __func__);
-
- /* update charger type */
- hisi_dwc->charger_type = detect_charger_type(hisi_dwc);
- if (sleep_allowed(hisi_dwc))
- hisi_dwc3_wake_unlock(hisi_dwc);
- else
- hisi_dwc3_wake_lock(hisi_dwc);
-
- /* do not start peripheral if real charger connected */
- if (enumerate_allowed(hisi_dwc)) {
- /* start peripheral */
- ret = dwc3_otg_work(dwc_otg_handler,
- DWC3_OTG_EVT_VBUS_SET);
- if (ret) {
- usb_err("start peripheral error\n");
- hisi_dwc->state = USB_STATE_OFF;
- pm_runtime_put(&hisi_dwc->pdev->dev);
- goto error;
- }
- } else {
- usb_dbg("a real charger connected\n");
- }
-
- break;
- case USB_STATE_HOST:
- usb_err("%s: host mode, should not go to sleep!\n", __func__);
- break;
- default:
- usb_err("%s: ilegal state!\n", __func__);
- break;
- }
-
-error:
- mutex_unlock(&hisi_dwc->lock);
-}
-
-static int hisi_dwc3_suspend(struct device *dev)
-{
- struct hisi_dwc3_device *hisi_dwc3 =
- platform_get_drvdata(to_platform_device(dev));
- int ret = 0;
-
- usb_dbg("+\n");
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return -EBUSY;
- }
-
- if (hisi_dwc3->runtime_suspended) {
- usb_dbg("runtime_suspended\n");
- } else {
- ret = hisi_dwc3_phy_shutdown(hisi_dwc3);
- if (ret)
- usb_err("hisi_dwc3_phy_shutdown failed\n");
- }
-
- usb_dbg("-\n");
-
- return ret;
-}
-
-static int hisi_dwc3_resume(struct device *dev)
-{
- struct hisi_dwc3_device *hisi_dwc3 =
- platform_get_drvdata(to_platform_device(dev));
- int ret = 0;
-
- usb_dbg("+\n");
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return -EBUSY;
- }
-
- if (hisi_dwc3->runtime_suspended) {
- usb_dbg("runtime_suspended\n");
- } else {
- ret = hisi_dwc3_phy_init(hisi_dwc3);
- if (ret)
- usb_err("hisi_dwc3_phy_init failed\n");
-
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
- usb_dbg("-\n");
-
- return ret;
-}
-#endif
-
-static int hisi_dwc3_runtime_suspend(struct device *dev)
-{
- int ret;
- struct hisi_dwc3_device *hisi_dwc3 =
- platform_get_drvdata(to_platform_device(dev));
-
- usb_dbg("+\n");
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return -EBUSY;
- }
-
- ret = hisi_dwc3_phy_shutdown(hisi_dwc3);
- if (ret)
- return ret;
- hisi_dwc3->runtime_suspended = 1;
- usb_dbg("-\n");
-
- return 0;
-}
-
-static int hisi_dwc3_runtime_resume(struct device *dev)
-{
- int ret = 0;
- struct hisi_dwc3_device *hisi_dwc3 =
- platform_get_drvdata(to_platform_device(dev));
-
- usb_dbg("+\n");
-
- if (!hisi_dwc3) {
- usb_err("hisi_dwc3 NULL\n");
- return -EBUSY;
- }
-
- ret = hisi_dwc3_phy_init(hisi_dwc3);
- if (ret)
- return ret;
- hisi_dwc3->runtime_suspended = 0;
- usb_dbg("-\n");
-
- return ret;
-}
-
-static int hisi_dwc3_runtime_idle(struct device *dev)
-{
- int ret;
-
- usb_dbg("+\n");
- ret = pm_runtime_autosuspend(dev);
- if (ret)
- dev_err(dev, "pm_runtime_autosuspend error\n");
- usb_dbg("-\n");
-
- return ret;
-}
-
-const struct dev_pm_ops hisi_dwc3_dev_pm_ops = {
-#ifdef CONFIG_PM_SLEEP
- .prepare = hisi_dwc3_prepare,
- .complete = hisi_dwc3_complete,
- SET_SYSTEM_SLEEP_PM_OPS(hisi_dwc3_suspend, hisi_dwc3_resume)
-#endif
- SET_RUNTIME_PM_OPS(hisi_dwc3_runtime_suspend, hisi_dwc3_runtime_resume,
- hisi_dwc3_runtime_idle)
-};
-#endif
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("wangbinghui<wangbinghui@hisilicon.com>");
+++ /dev/null
-/*
- * hisi_usb_vbus.h
- *
- * Copyright: (C) 2008-2018 hisilicon.
- * Contact: wangbinghui<wangbinghui@hisilicon.com>
- *
- * USB vbus for Hisilicon device
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose this file to be licensed under the terms
- * of the GNU General Public License (GPL) Version 2 or the 2-clause
- * BSD license listed below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- */
-#ifndef _DWC3_HISI_H_
-#define _DWC3_HISI_H_
-
-#include <linux/pm_wakeup.h>
-#include <linux/clk.h>
-#include <linux/hisi/usb/hisi_usb.h>
-#include <linux/regulator/consumer.h>
-
-#define REG_BASE_PERI_CRG (0xFFF35000)
-#define PERI_CRG_CLK_EN4 (0x40)
-#define PERI_CRG_CLK_DIS4 (0x44)
-#define PERI_CRG_RSTDIS4 (0x94)
-#define PERI_CRG_RSTEN4 (0x90)
-#define PERI_CRG_ISODIS (0x148)
-#define PERI_CRG_ISOSTAT (0x14C)
-#define STCL_ADDR (0xFFF0A214)
-#ifndef BIT
-#define BIT(x) (1 << (x))
-#endif
-#define PERI_CRG_ISOSTAT_MODEMSUBSYSISOEN BIT(4)
-#define PERI_CRG_ISODIS_MODEMSUBSYSISOEN BIT(4)
-
-#define PCTRL_PERI_CTRL24 (0x64)
-#define PCTRL_PERI_CTRL48 (0xC54)
-
-#define IP_RST_USB3OTG_MUX BIT(8)
-#define IP_RST_USB3OTG_AHBIF BIT(7)
-#define IP_RST_USB3OTG_32K BIT(6)
-#define IP_RST_USB3OTG BIT(5)
-#define IP_RST_USB3OTGPHY_POR BIT(3)
-
-#define GT_CLK_USB3OTG_REF BIT(0)
-#define GT_ACLK_USB3OTG BIT(1)
-#define GT_CLK_USB3PHY_REF BIT(2)
-
-/*
- * hisi dwc3 phy registers
- */
-#define DWC3_PHY_RX_OVRD_IN_HI 0x1006
-#define DWC3_PHY_RX_SCOPE_VDCC 0x1026
-
-/* DWC3_PHY_RX_SCOPE_VDCC */
-#define RX_SCOPE_LFPS_EN BIT(0)
-
-/*
- * hisi dwc3 otg bc registers
- */
-#define USBOTG3_CTRL0 0x00
-#define USBOTG3_CTRL1 0x04
-#define USBOTG3_CTRL2 0x08
-#define USBOTG3_CTRL3 0x0C
-#define USBOTG3_CTRL4 0x10
-#define USBOTG3_CTRL5 0x14
-#define USBOTG3_CTRL6 0x18
-#define USBOTG3_CTRL7 0x1C
-#define USBOTG3_STS0 0x20
-#define USBOTG3_STS1 0x24
-#define USBOTG3_STS2 0x28
-#define USBOTG3_STS3 0x2C
-#define BC_CTRL0 0x30
-#define BC_CTRL1 0x34
-#define BC_CTRL2 0x38
-#define BC_STS0 0x3C
-#define RAM_CTRL 0x40
-#define USBOTG3_STS4 0x44
-#define USB3PHY_CTRL 0x48
-#define USB3PHY_STS 0x4C
-#define USB3PHY_CR_STS 0x50
-#define USB3PHY_CR_CTRL 0x54
-#define USB3_RES 0x58
-
-/* USTOTG3_CTRL0 */
-# define USBOTG3CTRL0_SESSVLD_SEL BIT(14)
-# define USBOTG3CTRL0_SC_SESSVLD BIT(13)
-# define USBOTG3CTRL0_POWERPRESENT_SEL BIT(12)
-# define USBOTG3CTRL0_SC_POWERPRESENT BIT(11)
-# define USBOTG3CTRL0_BVALID_SEL BIT(10)
-# define USBOTG3CTRL0_SC_BVALID BIT(9)
-# define USBOTG3CTRL0_AVALID_SEL BIT(8)
-# define USBOTG3CTRL0_SC_AVALID BIT(7)
-# define USBOTG3CTRL0_VBUSVALID_SEL BIT(6)
-# define USBOTG3CTRL0_DRVVBUS BIT(5)
-# define USBOTG3CTRL0_DRVVBUS_SEL BIT(4)
-# define USBOTG3CTRL0_IDDIG BIT(3)
-# define USBOTG3CTRL0_IDDIG_SEL BIT(2)
-# define USBOTG3CTRL0_IDPULLUP BIT(1)
-# define USBOTG3CTRL0_IDPULLUP_SEL BIT(0)
-
-/* USTOTG3_CTRL2 */
-# define USBOTG3CTRL2_POWERDOWN_HSP BIT(0)
-# define USBOTG3CTRL2_POWERDOWN_SSP BIT(1)
-
-/* USBOTG3_CTRL3 */
-# define USBOTG3_CTRL3_VBUSVLDEXT BIT(6)
-# define USBOTG3_CTRL3_VBUSVLDEXTSEL BIT(5)
-# define USBOTG3_CTRL3_TXBITSTUFFEHN BIT(4)
-# define USBOTG3_CTRL3_TXBITSTUFFEN BIT(3)
-# define USBOTG3_CTRL3_RETENABLEN BIT(2)
-# define USBOTG3_CTRL3_OTGDISABLE BIT(1)
-# define USBOTG3_CTRL3_COMMONONN BIT(0)
-
-/* USBOTG3_CTRL4 */
-# define USBOTG3_CTRL4_TXVREFTUNE(x) (((x) << 22) & (0xf << 22))
-# define USBOTG3_CTRL4_TXRISETUNE(x) (((x) << 20) & (3 << 20))
-# define USBOTG3_CTRL4_TXRESTUNE(x) (((x) << 18) & (3 << 18))
-# define USBOTG3_CTRL4_TXPREEMPPULSETUNE BIT(17)
-# define USBOTG3_CTRL4_TXPREEMPAMPTUNE(x) (((x) << 15) & (3 << 15))
-# define USBOTG3_CTRL4_TXHSXVTUNE(x) (((x) << 13) & (3 << 13))
-# define USBOTG3_CTRL4_TXFSLSTUNE(x) (((x) << 9) & (0xf << 9))
-# define USBOTG3_CTRL4_SQRXTUNE(x) (((x) << 6) & (7 << 6))
-# define USBOTG3_CTRL4_OTGTUNE_MASK (7 << 3)
-# define USBOTG3_CTRL4_OTGTUNE(x) \
-(((x) << 3) & USBOTG3_CTRL4_OTGTUNE_MASK)
-# define USBOTG3_CTRL4_COMPDISTUNE_MASK 7
-# define USBOTG3_CTRL4_COMPDISTUNE(x) \
-((x) & USBOTG3_CTRL4_COMPDISTUNE_MASK)
-
-# define USBOTG3_CTRL7_REF_SSP_EN BIT(16)
-
-/* USBOTG3_CTRL6 */
-#define TX_VBOOST_LVL_MASK 7
-#define TX_VBOOST_LVL(x) ((x) & TX_VBOOST_LVL_MASK)
-
-/* BC_CTRL0 */
-# define BC_CTRL0_BC_IDPULLUP BIT(10)
-# define BC_CTRL0_BC_SUSPEND_N BIT(9)
-# define BC_CTRL0_BC_DMPULLDOWN BIT(8)
-# define BC_CTRL0_BC_DPPULLDOWN BIT(7)
-# define BC_CTRL0_BC_TXVALIDH BIT(6)
-# define BC_CTRL0_BC_TXVALID BIT(5)
-# define BC_CTRL0_BC_TERMSELECT BIT(4)
-# define BC_CTRL0_BC_XCVRSELECT(x) (((x) << 2) & (3 << 2))
-# define BC_CTRL0_BC_OPMODE(x) ((x) & 3)
-
-/* BC_CTRL1 */
-# define BC_CTRL1_BC_MODE 1
-
-/* BC_CTRL2 */
-# define BC_CTRL2_BC_PHY_VDATDETENB BIT(4)
-# define BC_CTRL2_BC_PHY_VDATARCENB BIT(3)
-# define BC_CTRL2_BC_PHY_CHRGSEL BIT(2)
-# define BC_CTRL2_BC_PHY_DCDENB BIT(1)
-# define BC_CTRL2_BC_PHY_ACAENB BIT(0)
-
-/* BC_STS0 */
-# define BC_STS0_BC_LINESTATE(x) (((x) << 9) & (3 << 9))
-# define BC_STS0_BC_PHY_CHGDET BIT(8)
-# define BC_STS0_BC_PHY_FSVMINUS BIT(7)
-# define BC_STS0_BC_PHY_FSVPLUS BIT(6)
-# define BC_STS0_BC_RID_GND BIT(5)
-# define BC_STS0_BC_RID_FLOAT BIT(4)
-# define BC_STS0_BC_RID_C BIT(3)
-# define BC_STS0_BC_RID_B BIT(2)
-# define BC_STS0_BC_RID_A BIT(1)
-# define BC_STS0_BC_SESSVLD BIT(0)
-
-/* USB3PHY_CR_STS */
-#define USB3OTG_PHY_CR_DATA_OUT(x) (((x) >> 1) & 0xffff)
-#define USB3OTG_PHY_CR_ACK BIT(0)
-
-/* USB3PHY_CR_CTRL */
-#define USB3OTG_PHY_CR_DATA_IN(x) (((x) << 4) & (0xffff << 4))
-#define USB3OTG_PHY_CR_WRITE BIT(3)
-#define USB3OTG_PHY_CR_READ BIT(2)
-#define USB3OTG_PHY_CR_CAP_DATA BIT(1)
-#define USB3OTG_PHY_CR_CAP_ADDR BIT(0)
-
-#define usb_dbg(format, arg...) \
- pr_err("[USB3][%s]"format, __func__, ##arg)
-
-#define usb_err(format, arg...) \
- pr_err("[USB3][%s]"format, __func__, ##arg)
-
-enum hisi_usb_state {
- USB_STATE_UNKNOWN = 0,
- USB_STATE_OFF,
- USB_STATE_DEVICE,
- USB_STATE_HOST,
-};
-
-struct hiusb_event_queue {
- enum otg_dev_event_type *event;
- unsigned int num_event;
- unsigned int max_event;
- unsigned int enpos, depos;
- unsigned int overlay, overlay_index;
-};
-
-#define MAX_EVENT_COUNT 16
-#define EVENT_QUEUE_UNIT MAX_EVENT_COUNT
-
-struct hisi_dwc3_device {
- struct platform_device *pdev;
-
- void __iomem *otg_bc_reg_base;
- void __iomem *pericfg_reg_base;
- void __iomem *pctrl_reg_base;
- void __iomem *sctrl_reg_base;
-
- struct regulator *usb_regu;
- unsigned int is_regu_on;
- unsigned int runtime_suspended;
-
- enum hisi_usb_state state;
- enum hisi_charger_type charger_type;
- enum hisi_charger_type fake_charger_type;
-
- enum otg_dev_event_type event;
- spinlock_t event_lock;
-
- struct mutex lock;
- struct wakeup_source ws;
- struct atomic_notifier_head charger_type_notifier;
- struct work_struct event_work;
-
- u32 eye_diagram_param; /* this param will be set to USBOTG3_CTRL4 */
- u32 eye_diagram_host_param;
- u32 usb3_phy_cr_param;
- u32 usb3_phy_host_cr_param;
- u32 usb3_phy_tx_vboost_lvl;
- unsigned int host_flag;
-
- u32 fpga_flag;
- int fpga_usb_mode_gpio;
-
- struct clk *clk;
- struct clk *gt_aclk_usb3otg;
-
- int eventmask;
-
- /* for bc again */
- u32 bc_again_flag;
- struct delayed_work bc_again_work;
- struct notifier_block conndone_nb;
-
- /* event queue for handle event */
- struct hiusb_event_queue event_queue;
-
- struct usb3_phy_ops *phy_ops;
-
- unsigned int need_disable_vdp;
- void (*disable_vdp_src)(struct hisi_dwc3_device *hisi_dwc3);
-};
-
-#ifdef CONFIG_PM
-extern const struct dev_pm_ops hisi_dwc3_dev_pm_ops;
-#define HISI_DWC3_PM_OPS (&hisi_dwc3_dev_pm_ops)
-#else
-#define HISI_DWC3_PM_OPS NULL
-#endif
-
-struct usb3_phy_ops {
- struct regulator *subsys_regu;
-
- int (*init)(struct hisi_dwc3_device *hisi_dwc3);
- int (*shutdown)(struct hisi_dwc3_device *hisi_dwc3);
-};
-
-typedef ssize_t (*hiusb_debug_show_ops)(void *, char *, ssize_t);
-typedef ssize_t (*hiusb_debug_store_ops)(void *, const char *, ssize_t);
-void hiusb_debug_init(void *data);
-void hiusb_debug_quick_register(void *dev_data,
- hiusb_debug_show_ops show,
- hiusb_debug_store_ops store);
-
-void set_hisi_dwc3_power_flag(int val);
-void config_femtophy_param(struct hisi_dwc3_device *hisi_dwc);
-int hisi_dwc3_probe(struct platform_device *pdev, struct usb3_phy_ops *phy_ops);
-int hisi_dwc3_remove(struct platform_device *pdev);
-#endif /* _DWC3_HISI_H_ */
+++ /dev/null
-/*
- * dwc3-otg.c
- *
- * Copyright: (C) 2008-2018 hisilicon.
- * Contact: wangbinghui<wangbinghui@hisilicon.com>
- *
- * USB vbus for Hisilicon device
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose this file to be licensed under the terms
- * of the GNU General Public License (GPL) Version 2 or the 2-clause
- * BSD license listed below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- */
-#include <linux/kernel.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
-
-#include "core.h"
-#include "io.h"
-#include "dwc3-otg.h"
-
-#define DBG(format, arg...) pr_info("[%s]" format, __func__, ##arg)
-
-struct dwc3_otg *dwc_otg_handler;
-
-static void dump_otg_regs(struct dwc3 *dwc)
-{
-#define DUMP_REG(__reg) pr_info("%s:\t0x%x\n", \
- #__reg, dwc3_readl(dwc->regs, __reg))
- DUMP_REG(DWC3_OCFG);
- DUMP_REG(DWC3_OCTL);
- DUMP_REG(DWC3_OEVT);
- DUMP_REG(DWC3_OEVTEN);
- DUMP_REG(DWC3_OSTS);
-
- DUMP_REG(DWC3_BCFG);
- DUMP_REG(DWC3_BCEVT);
- DUMP_REG(DWC3_BCEVTEN);
-}
-
-#ifndef DWC3_OTG_FORCE_MODE
-static void dwc3_disable_otg_event(struct dwc3 *dwc)
-{
- dwc3_writel(dwc->regs, DWC3_OEVT, 0x0ffffff0);
- dwc3_writel(dwc->regs, DWC3_OEVTEN, 0);
-}
-
-static void dwc3_enable_otg_event(struct dwc3 *dwc)
-{
- dwc3_writel(dwc, DWC3_OEVTEN, 0);
- dwc3_writel(dwc->regs, DWC3_OEVT, 0x0ffffff0);
- dwc3_writel(dwc->regs, DWC3_OEVTEN, DWC3_OEVT_OTGBDEVVBUSCHNGEVNT |
- DWC3_OEVT_OTGCONIDSTSCHNGEVNT);
-}
-#endif
-
-int dwc3_otg_resume(struct dwc3 *dwc)
-{
- DBG("+\n");
-#ifndef DWC3_OTG_FORCE_MODE
- u32 reg;
-
- reg = dwc3_readl(dwc->regs, DWC3_OSTS);
- if (reg & DWC3_OSTS_CONIDSTS) {
- DBG("%s: ID is 1, set peripheral mode\n", __func__);
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg |= DWC3_OCTL_PERIMODE;
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
- } else {
- DBG("%s: ID is 0, clear peripheral mode\n", __func__);
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg &= ~DWC3_OCTL_PERIMODE;
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
- }
-#endif
-
- DBG("-\n");
-
- return 0;
-}
-
-int dwc3_otg_suspend(struct dwc3 *dwc)
-{
- DBG("+\n");
- DBG("-\n");
- return 0;
-}
-
-static int dwc3_otg_start_host(struct dwc3_otg *dwc_otg)
-{
- struct dwc3 *dwc = dwc_otg->dwc;
- unsigned long flags;
- int ret;
- u32 reg;
-
- DBG("+\n");
-
- spin_lock_irqsave(&dwc->lock, flags);
-
-#ifdef DWC3_OTG_FORCE_MODE
- reg = dwc3_readl(dwc->regs, DWC3_GCTL);
- pr_debug("%s: GCTL value 0x%x\n", __func__, reg);
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
-#else
- /* check ID ststus */
- DBG("+before read DWC3_OSTS\n");
- reg = dwc3_readl(dwc->regs, DWC3_OSTS);
- if (reg & DWC3_OSTS_CONIDSTS) {
- pr_warn("%s: CONIDSTS wrong!\n");
- dump_otg_regs(dwc);
- }
- DBG("+before read DWC3_OCFG\n");
- reg = dwc3_readl(dwc->regs, DWC3_OCFG);
- reg |= DWC3_OCFG_OTGSFTRSTMSK;
- reg |= DWC3_OCFG_DISPRTPWRCUTOFF;
- reg &= ~(DWC3_OCFG_HNPCAP | DWC3_OCFG_SRPCAP);
- dwc3_writel(dwc->regs, DWC3_OCFG, reg);
-
- DBG("set OCFG 0x%x\n", dwc3_readl(dwc->regs, DWC3_OCFG));
-
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg &= ~DWC3_OCTL_PERIMODE;
- reg |= DWC3_OCTL_PRTPWRCTL;
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
-
- DBG("set OCTL 0x%x\n", dwc3_readl(dwc->regs, DWC3_OCTL));
-#endif
-
- spin_unlock_irqrestore(&dwc->lock, flags);
-
- ret = platform_device_add(dwc->xhci);
- if (ret) {
- pr_err("%s: failed to register xHCI device\n", __func__);
- return ret;
- }
-
-#ifdef CONFIG_HISI_USB_DWC3_MASK_IRQ_WORKAROUND
- if (dwc->irq_state == 0) {
- enable_irq(dwc->irq);
- dwc->irq_state = 1;
- pr_info("[%s]enable irq\n", __func__);
- }
-#endif
-
- DBG("-\n");
-
- return ret;
-}
-
-static void dwc3_otg_stop_host(struct dwc3_otg *dwc_otg)
-{
- DBG("+\n");
- platform_device_del(dwc_otg->dwc->xhci);
- DBG("-\n");
-}
-
-static int dwc3_otg_start_peripheral(struct dwc3_otg *dwc_otg)
-{
- int ret;
- unsigned long flags;
- struct dwc3 *dwc = dwc_otg->dwc;
- u32 reg;
-
- DBG("+\n");
-
- spin_lock_irqsave(&dwc->lock, flags);
-
-#ifdef DWC3_OTG_FORCE_MODE
- reg = dwc3_readl(dwc->regs, DWC3_GCTL);
- pr_debug("%s: GCTL value 0x%x\n", __func__, reg);
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-#else
- reg = dwc3_readl(dwc->regs, DWC3_OSTS);
- if (!(reg & DWC3_OSTS_CONIDSTS) || !(reg & DWC3_OSTS_BSESVLD)) {
- pr_warn("%s: CONIDSTS or BSESVLD wrong!\n");
- dump_otg_regs(dwc);
- }
-
- /* set mode as peripheral */
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg |= DWC3_OCTL_PERIMODE;
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
-#endif
-
- ret = dwc3_gadget_resume(dwc);
- if (ret)
- pr_err("[%s] gadget resume error!", __func__);
-
- spin_unlock_irqrestore(&dwc->lock, flags);
- DBG("-\n");
-
- return ret;
-}
-
-static int dwc3_otg_stop_peripheral(struct dwc3_otg *dwc_otg)
-{
- int ret;
- unsigned long flags;
- struct dwc3 *dwc = dwc_otg->dwc;
-
- DBG("+\n");
- spin_lock_irqsave(&dwc->lock, flags);
-
- ret = dwc3_gadget_suspend(dwc);
- if (ret)
- pr_err("[%s] gadget suspend error!", __func__);
-
- spin_unlock_irqrestore(&dwc->lock, flags);
- DBG("-\n");
-
- return ret;
-}
-
-int dwc3_otg_id_value(struct dwc3_otg *dwc_otg)
-{
- if (dwc_otg)
- return !!(dwc3_readl(dwc_otg->dwc->regs, DWC3_OSTS)
- & DWC3_OSTS_CONIDSTS);
- else
- return 1;
-}
-
-int dwc3_otg_work(struct dwc3_otg *dwc_otg, int evt)
-{
- int ret = 0;
-
- DBG("+\n evt = %d", evt);
-
- /* if otg is not enabled, do nothing */
- if (!dwc_otg) {
- pr_info("%s: dwc3 is not otg mode!\n", __func__);
- return 0;
- }
-
- switch (evt) {
- case DWC3_OTG_EVT_ID_SET:
- dwc3_otg_stop_host(dwc_otg);
- dwc3_suspend_device(dwc_otg->dwc);
- break;
- case DWC3_OTG_EVT_ID_CLEAR:
- ret = dwc3_resume_device(dwc_otg->dwc);
- if (ret) {
- pr_err("%s: resume device failed!\n", __func__);
- return ret;
- }
- ret = dwc3_otg_start_host(dwc_otg);
- if (ret) {
- pr_err("%s: start host failed!\n", __func__);
- dwc3_suspend_device(dwc_otg->dwc);
- return ret;
- }
- break;
- case DWC3_OTG_EVT_VBUS_SET:
- ret = dwc3_resume_device(dwc_otg->dwc);
- if (ret) {
- pr_err("%s: resume device failed!\n", __func__);
- return ret;
- }
- ret = dwc3_otg_start_peripheral(dwc_otg);
- if (ret) {
- pr_err("%s: start peripheral failed!\n", __func__);
- dwc3_suspend_device(dwc_otg->dwc);
- return ret;
- }
- break;
- case DWC3_OTG_EVT_VBUS_CLEAR:
- ret = dwc3_otg_stop_peripheral(dwc_otg);
- dwc3_suspend_device(dwc_otg->dwc);
- break;
- default:
- break;
- }
- DBG("-\n");
-
- return ret;
-}
-
-static void dwc3_otg_work_fun(struct work_struct *w)
-{
- struct dwc3_otg *dwc_otg = container_of(
- w, struct dwc3_otg, otg_work.work);
-
- mutex_lock(&dwc_otg->lock);
- if (dwc3_otg_work(dwc_otg, atomic_read(&dwc_otg->otg_evt_flag)))
- pr_err("%s: dwc3_otg_work failed\n", __func__);
- mutex_unlock(&dwc_otg->lock);
-}
-
-int dwc3_hisi_otg_init(struct dwc3 *dwc)
-{
- struct dwc3_otg *dwc_otg;
- u32 reg;
-
- DBG("+\n");
-
- dwc_otg = devm_kzalloc(dwc->dev, sizeof(struct dwc3_otg), GFP_KERNEL);
- if (!dwc_otg) {
- dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
- return -ENOMEM;
- }
-
- dwc_otg->dwc = dwc;
- dwc->dwc_otg = dwc_otg;
-
- mutex_init(&dwc_otg->lock);
- INIT_DELAYED_WORK(&dwc_otg->otg_work, dwc3_otg_work_fun);
-
- dwc_otg_handler = dwc_otg;
-
-#ifdef DWC3_OTG_FORCE_MODE
- reg = dwc3_readl(dwc->regs, DWC3_GCTL);
- pr_debug("%s: GCTL value 0x%x\n", __func__, reg);
-
- /* default device mode */
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
-#else
- /* disable hnp and srp */
- reg = dwc3_readl(dwc->regs, DWC3_OCFG);
- reg &= ~(DWC3_OCFG_HNPCAP | DWC3_OCFG_SRPCAP);
- dwc3_writel(dwc->regs, DWC3_OCFG, reg);
-
- reg = dwc3_readl(dwc->regs, DWC3_OSTS);
- if (reg & DWC3_OSTS_CONIDSTS) {
- DBG("%s: ID is 1, set peripheral mode\n", __func__);
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg |= DWC3_OCTL_PERIMODE;
- reg &= ~(DWC3_OCTL_HNPREQ | DWC3_OCTL_DEVSETHNPEN |
- DWC3_OCTL_HSTSETHNPEN);
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
- } else {
- DBG("%s: ID is 0, clear peripheral mode\n", __func__);
- reg = dwc3_readl(dwc->regs, DWC3_OCTL);
- reg &= ~DWC3_OCTL_PERIMODE;
- dwc3_writel(dwc->regs, DWC3_OCTL, reg);
- }
-#endif
-
- dump_otg_regs(dwc);
-
- DBG("-\n");
-
- return 0;
-}
-
-void dwc3_hisi_otg_exit(struct dwc3 *dwc)
-{
- DBG("+\n");
- dwc_otg_handler = NULL;
- dwc->dwc_otg->dwc = NULL;
- dwc->dwc_otg = NULL;
- DBG("-\n");
-}
+++ /dev/null
-/*
- * dwc3-otg.h
- *
- * Copyright: (C) 2008-2018 hisilicon.
- * Contact: wangbinghui<wangbinghui@hisilicon.com>
- *
- * USB vbus for Hisilicon device
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose this file to be licensed under the terms
- * of the GNU General Public License (GPL) Version 2 or the 2-clause
- * BSD license listed below:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- */
-#ifndef __DRIVERS_USB_DWC3_OTG_H
-#define __DRIVERS_USB_DWC3_OTG_H
-
-/* BC Registers */
-#define DWC3_BCFG 0xcc30
-#define DWC3_BCEVT 0xcc38
-#define DWC3_BCEVTEN 0xcc3c
-#ifndef BIT
-#define BIT(x) (1 << (x))
-#endif
-/* OTG Configuration Register */
-#define DWC3_OCFG_DISPRTPWRCUTOFF BIT(5)
-#define DWC3_OCFG_OTGHIBDISMASK BIT(4)
-#define DWC3_OCFG_OTGSFTRSTMSK BIT(3)
-#define DWC3_OCFG_HNPCAP BIT(1)
-#define DWC3_OCFG_SRPCAP_OLD 1
-
-/* OTG Control Register */
-#define DWC3_OCTL_OTG3_GOERR BIT(7)
-#define DWC3_OCTL_PERIMODE BIT(6)
-#define DWC3_OCTL_PRTPWRCTL BIT(5)
-#define DWC3_OCTL_HNPREQ BIT(4)
-#define DWC3_OCTL_SESREQ BIT(3)
-#define DWC3_OCTL_TERMSELDLPULSE BIT(2)
-#define DWC3_OCTL_DEVSETHNPEN BIT(1)
-#define DWC3_OCTL_HSTSETHNPEN BIT(0)
-
-/* OTG Events Register */
-#define DWC3_OEVT_DEVICEMOD BIT(31)
-#define DWC3_OEVT_OTGXHCIRUNSTPSETEVNT BIT(27)
-#define DWC3_OEVT_OTGDEVRUNSTPSETEVNT BIT(26)
-#define DWC3_OEVT_OTGHIBENTRYEVNT BIT(25)
-#define DWC3_OEVT_OTGCONIDSTSCHNGEVNT BIT(24)
-#define DWC3_OEVT_HRRCONFNOTIFEVNT BIT(23)
-#define DWC3_OEVT_HRRINITNOTIFEVNT BIT(22)
-#define DWC3_OEVT_OTGADEVIDLEEVNT BIT(21)
-#define DWC3_OEVT_OTGADEVBHOSTENDEVNT BIT(20)
-#define DWC3_OEVT_OTGADEVHOSTEVNT BIT(19)
-#define DWC3_OEVT_OTGADEVHNPCHNGEVNT BIT(18)
-#define DWC3_OEVT_OTGADEVSRPDETEVNT BIT(17)
-#define DWC3_OEVT_OTGADEVSESSENDDETEVNT BIT(16)
-#define DWC3_OEVT_OTGBDEVBHOSTENDEVNT BIT(11)
-#define DWC3_OEVT_OTGBDEVHNPCHNGEVNT BIT(10)
-#define DWC3_OEVT_OTGBDEVSESSVLDDETEVNT BIT(9)
-#define DWC3_OEVT_OTGBDEVVBUSCHNGEVNT BIT(8)
-
-/* OTG Status Register */
-#define DWC3_OSTS_OTGSTATE_MSK (0xf << 8)
-#define DWC3_OSTS_PERIPHERALSTATE BIT(4)
-#define DWC3_OSTS_XHCIPRTPOWER BIT(3)
-#define DWC3_OSTS_BSESVLD BIT(2)
-#define DWC3_OSTS_ASESVLD BIT(1)
-#define DWC3_OSTS_CONIDSTS BIT(0)
-
-struct dwc3_otg {
- struct usb_otg otg;
- struct dwc3 *dwc;
- int otg_irq;
- struct delayed_work otg_work;
-
- atomic_t otg_evt_flag;
-#define DWC3_OTG_EVT_ID_SET 1
-#define DWC3_OTG_EVT_ID_CLEAR 2
-#define DWC3_OTG_EVT_VBUS_SET 3
-#define DWC3_OTG_EVT_VBUS_CLEAR 4
-
- struct mutex lock;
-};
-
-#ifdef CONFIG_USB_DWC3_OTG
-extern struct dwc3_otg *dwc_otg_handler;
-int dwc3_hisi_otg_init(struct dwc3 *dwc);
-void dwc3_hisi_otg_exit(struct dwc3 *dwc);
-int dwc3_otg_work(struct dwc3_otg *dwc_otg, int evt);
-int dwc3_otg_resume(struct dwc3 *dwc);
-int dwc3_otg_suspend(struct dwc3 *dwc);
-int dwc3_otg_id_value(struct dwc3_otg *dwc_otg);
-#else
-#define dwc_otg_handler ((struct dwc3_otg *)NULL)
-static inline int dwc3_hisi_otg_init(struct dwc3 *dwc)
-{
- return 0;
-}
-
-static inline void dwc3_hisi_otg_exit(struct dwc3 *dwc)
-{
-}
-
-static inline int dwc3_otg_work(struct dwc3_otg *dwc_otg, int evt)
-{
- return 0;
-}
-
-static inline int dwc3_otg_resume(struct dwc3 *dwc)
-{
- return 0;
-}
-
-static inline int dwc3_otg_suspend(struct dwc3 *dwc)
-{
- return 0;
-}
-
-static inline int dwc3_otg_id_value(struct dwc3_otg *dwc_otg)
-{
- return 0;
-};
-#endif
-
-#endif /* __DRIVERS_USB_DWC3_OTG_H */
struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
- int ret;
req->request.actual = 0;
req->request.status = -EINPROGRESS;
req->epnum = dep->number;
- /* we share one TRB for ep0/1 */
- if (!list_empty(&dep->pending_list)) {
- dev_WARN(dwc->dev, "ep0 busy!\n");
- ret = -EBUSY;
- return ret;
- }
-
list_add_tail(&req->list, &dep->pending_list);
/*
__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
dep->flags &= ~DWC3_EP0_DIR_IN;
-
- return 0;
}
- /* mark the status phase already queued */
- if (dwc->ep0_next_event == DWC3_EP0_NRDY_STATUS)
- dwc->status_queued = true;
-
- if (req->request.length != 0)
- dev_WARN(dwc->dev, "status phase len %d\n",
- req->request.length);
-
return 0;
}
goto out;
}
+ /* we share one TRB for ep0/1 */
+ if (!list_empty(&dep->pending_list)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = __dwc3_gadget_ep0_queue(dep, req);
out:
__dwc3_gadget_ep_set_halt(dep, 1, false);
dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false;
- dwc->status_queued = false;
if (!list_empty(&dep->pending_list)) {
struct dwc3_request *req;
if (value != 0)
return -EINVAL;
- if (!(ctrl->bRequestType & USB_DIR_IN))
- return -EINVAL;
-
- if (!le16_to_cpu(ctrl->wLength))
- return -EINVAL;
-
recip = ctrl->bRequestType & USB_RECIP_MASK;
switch (recip) {
case USB_RECIP_DEVICE:
enum usb_device_state state = dwc->gadget.state;
u16 wLength;
- if (unlikely(ctrl->bRequestType & USB_DIR_IN))
- return -EINVAL;
-
- if (unlikely(!le16_to_cpu(ctrl->wLength)))
- return -EINVAL;
-
if (state == USB_STATE_DEFAULT)
return -EINVAL;
if (ret == USB_GADGET_DELAYED_STATUS)
dwc->delayed_status = true;
- if (dwc->status_queued) {
- dwc->status_queued = false;
- if (dwc->delayed_status) {
- pr_info("delayed status already come, will not wait for it.\n");
- dwc->delayed_status = false;
- usb_gadget_set_state(&dwc->gadget,
- USB_STATE_CONFIGURED);
- }
- }
-
out:
- if (ret < 0) {
- dev_err(dwc->dev, "ep0 setup error, ret %d!\n", ret);
- dev_err(dwc->dev, "ctrl: %02x %02x %04x %04x %04x\n",
- ctrl->bRequestType, ctrl->bRequest,
- ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+ if (ret < 0)
dwc3_ep0_stall_and_restart(dwc);
- }
-
}
static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trace_dwc3_complete_trb(ep0, trb);
r = next_request(&ep0->pending_list);
- if (!r) {
- dev_err(dwc->dev, "ep0 request list empty while complete data\n");
+ if (!r)
return;
- }
status = DWC3_TRB_SIZE_TRBSTS(trb->size);
if (status == DWC3_TRBSTS_SETUP_PENDING) {
return;
}
- dwc->status_queued = false;
-
dwc3_ep0_do_control_status(dwc, event);
}
}
#include "core.h"
#include "gadget.h"
#include "io.h"
-#include "dwc3-hisi.h"
#define DWC3_ALIGN_FRAME(d) (((d)->frame_number + (d)->interval) \
& ~((d)->interval - 1))
{
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
struct dwc3 *dwc = dep->dwc;
- u32 timeout = 3000;
+ u32 timeout = 1000;
u32 reg;
int cmd_status = 0;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
}
-ATOMIC_NOTIFIER_HEAD(conndone_nh);
-
-int dwc3_conndone_notifier_register(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&conndone_nh, nb);
-}
-
-int dwc3_conndone_notifier_unregister(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&conndone_nh, nb);
-}
-
static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
-#ifndef CONFIG_USB_DWC3_HISI
dwc->gadget.is_otg = dwc->dr_mode == USB_DR_MODE_OTG;
-#endif
/*
* FIXME We might be setting max_speed to <SUPER, however versions
goto err1;
}
-#ifdef CONFIG_USB_DWC3_HISI
- /* if otg, otg will do device_add */
- if (dwc->dwc_otg) {
- dev_err(dwc->dev, "%s if otg, otg will do device_add.\n",
- __func__);
- return 0;
- }
-#endif
-
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
if (dwc->usb3_lpm_capable)
void dwc3_host_exit(struct dwc3 *dwc)
{
-#ifdef CONFIG_USB_DWC3_HISI
- if (dwc->dwc_otg)
- return;
-#endif
phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
dev_name(dwc->dev));
phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
{
u32 value;
-#ifdef CONFIG_USB_DWC3_HISI
- extern atomic_t hisi_dwc3_power_on;
-
- if (unlikely(atomic_read(&hisi_dwc3_power_on) == 0))
- return 0;
-#endif
-
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
-#ifdef CONFIG_USB_DWC3_HISI
- extern atomic_t hisi_dwc3_power_on;
-
- if (unlikely(atomic_read(&hisi_dwc3_power_on) == 0))
- return;
-#endif
-
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
+++ /dev/null
-source "drivers/usb/pd/richtek/Kconfig"
+++ /dev/null
-obj-y += hisi_pd.o
-obj-y += richtek/
+++ /dev/null
-/************************************************************
- *
- * Copyright (C), Hisilicon Tech. Co., Ltd.
- * FileName: hisi_pd.c
- * Author: Hisilicon Version : 0.1 Date: 2016-5-9
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Description: .c file for power delivery core layer which is used to handle
- * pulic logic management for different chips and to
- * provide interfaces for exteranl modules.
- * Version:
- * Function List:
- * History:
- * <author> <time> <version > <desc>
- ***********************************************************/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/notifier.h>
-#include <linux/mutex.h>
-#include <linux/version.h>
-#include <linux/hisi/log/hisi_log.h>
-#include <linux/hisi/usb/hisi_pd_dev.h>
-#include <linux/hisi/usb/hisi_usb.h>
-#include <linux/hisi/usb/pd/richtek/tcpm.h>
-
-struct pd_dpm_info *g_pd_di;
-static bool g_pd_cc_orientation;
-static struct class *typec_class;
-static struct device *typec_dev;
-static int pd_dpm_typec_state;
-
-#ifndef HISILOG_TAG
-#define HISILOG_TAG hisi_pd
-HISILOG_REGIST();
-#endif
-
-static bool pd_dpm_get_cc_orientation(void)
-{
- hisilog_info("%s cc_orientation =%d\n", __func__, g_pd_cc_orientation);
- return g_pd_cc_orientation;
-}
-
-static void pd_dpm_set_cc_orientation(bool cc_orientation)
-{
- hisilog_info("%s cc_orientation =%d\n", __func__, cc_orientation);
- g_pd_cc_orientation = cc_orientation;
-}
-
-void pd_dpm_get_typec_state(int *typec_state)
-{
- hisilog_info("%s = %d\n",
- __func__, pd_dpm_typec_state);
-
- *typec_state = pd_dpm_typec_state;
-}
-
-static void pd_dpm_set_typec_state(int typec_state)
-{
- hisilog_info("%s = %d\n",
- __func__, typec_state);
-
- pd_dpm_typec_state = typec_state;
-}
-
-static ssize_t pd_dpm_cc_orientation_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%s\n",
- pd_dpm_get_cc_orientation() ? "2" : "1");
-}
-
-static ssize_t pd_dpm_pd_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%s\n",
- pd_dpm_get_pd_finish_flag() ? "0" : "1");
-}
-
-static DEVICE_ATTR(cc_orientation, 0444, pd_dpm_cc_orientation_show, NULL);
-static DEVICE_ATTR(pd_state, 0444, pd_dpm_pd_state_show, NULL);
-
-static struct attribute *pd_dpm_ctrl_attributes[] = {
- &dev_attr_cc_orientation.attr,
- &dev_attr_pd_state.attr,
- NULL,
-};
-
-static const struct attribute_group pd_dpm_attr_group = {
- .attrs = pd_dpm_ctrl_attributes,
-};
-
-int pd_dpm_wake_unlock_notifier_call(struct pd_dpm_info *di,
- unsigned long event, void *data)
-{
- return atomic_notifier_call_chain(&di->pd_wake_unlock_evt_nh,
- event, data);
-}
-
-int pd_dpm_vbus_notifier_call(struct pd_dpm_info *di, unsigned long event,
- void *data)
-{
- hisilog_err("%s: pd_dpm_vbus_notifier_call!!!,++++\n",
- __func__);
- return atomic_notifier_call_chain(&di->pd_evt_nh, event, data);
-}
-
-bool pd_dpm_get_pd_finish_flag(void)
-{
- if (g_pd_di)
- return g_pd_di->pd_finish_flag;
- else
- return false;
-}
-
-bool pd_dpm_get_pd_source_vbus(void)
-{
- if (g_pd_di)
- return g_pd_di->pd_source_vbus;
- else
- return false;
-}
-
-void pd_dpm_report_pd_source_vbus(struct pd_dpm_info *di, void *data)
-{
- struct pd_dpm_vbus_state *vbus_state = data;
-
- mutex_lock(&di->sink_vbus_lock);
-
- if (vbus_state->vbus_type & TCP_VBUS_CTRL_PD_DETECT)
- di->pd_finish_flag = true;
-
- if (vbus_state->mv == 0) {
- hisilog_info("%s : Disable\n", __func__);
- pd_dpm_vbus_notifier_call(g_pd_di, CHARGER_TYPE_NONE, data);
- } else {
- di->pd_source_vbus = true;
- hisilog_info("%s : Source %d mV, %d mA\n",
- __func__, vbus_state->mv, vbus_state->ma);
- pd_dpm_vbus_notifier_call(g_pd_di, PLEASE_PROVIDE_POWER, data);
- }
- mutex_unlock(&di->sink_vbus_lock);
-}
-
-void pd_dpm_report_pd_sink_vbus(struct pd_dpm_info *di, void *data)
-{
- bool skip = false;
- unsigned long event;
- struct pd_dpm_vbus_state *vbus_state = data;
-
- mutex_lock(&di->sink_vbus_lock);
-
- if (vbus_state->vbus_type & TCP_VBUS_CTRL_PD_DETECT)
- di->pd_finish_flag = true;
-
- if (di->pd_finish_flag)
- event = PD_DPM_VBUS_TYPE_PD;
- else if (di->bc12_finish_flag)
- skip = true;
- else
- event = PD_DPM_VBUS_TYPE_TYPEC;
-
- if (!skip) {
- vbus_state = data;
-
- if (vbus_state->mv == 0) {
- if (event == PD_DPM_VBUS_TYPE_PD) {
- hisilog_info("%s : Disable\n", __func__);
- pd_dpm_vbus_notifier_call(g_pd_di,
- CHARGER_TYPE_NONE,
- data);
- }
- } else {
- di->pd_source_vbus = false;
- hisilog_info("%s : Sink %d mV, %d mA\n",
- __func__, vbus_state->mv, vbus_state->ma);
- pd_dpm_vbus_notifier_call(g_pd_di, event, data);
- }
- } else {
- hisilog_info("%s : skip\n", __func__);
- }
-
- mutex_unlock(&di->sink_vbus_lock);
-}
-
-int pd_dpm_report_bc12(struct notifier_block *usb_nb, unsigned long event,
- void *data)
-{
- struct pd_dpm_info *di = container_of(usb_nb,
- struct pd_dpm_info, usb_nb);
-
- if (event == CHARGER_TYPE_NONE && !di->pd_finish_flag) {
- di->bc12_finish_flag = false;
- hisilog_info("%s : PD_WAKE_UNLOCK\n",
- __func__);
- pd_dpm_wake_unlock_notifier_call(g_pd_di, PD_WAKE_UNLOCK, NULL);
- }
-
- if (event == PLEASE_PROVIDE_POWER)
- return NOTIFY_OK;
-
- if (!di->pd_finish_flag) {
- hisilog_info("%s : event (%lu)\n", __func__, event);
- pd_dpm_vbus_notifier_call(di, event, data);
- } else {
- hisilog_info("%s : igrone\n", __func__);
- }
-
- return NOTIFY_OK;
-}
-
-int register_pd_wake_unlock_notifier(struct notifier_block *nb)
-{
- int ret = 0;
-
- if (!nb)
- return -EINVAL;
-
- if (!g_pd_di)
- return ret;
-
- ret = atomic_notifier_chain_register(&g_pd_di->pd_wake_unlock_evt_nh,
- nb);
- if (ret != 0)
- return ret;
-
- return ret;
-}
-EXPORT_SYMBOL(register_pd_wake_unlock_notifier);
-
-int unregister_pd_wake_unlock_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister
- (&g_pd_di->pd_wake_unlock_evt_nh, nb);
-}
-EXPORT_SYMBOL(unregister_pd_wake_unlock_notifier);
-
-int register_pd_dpm_notifier(struct notifier_block *nb)
-{
- int ret = 0;
-
- if (!nb)
- return -EINVAL;
-
- if (!g_pd_di)
- return ret;
-
- ret = atomic_notifier_chain_register(&g_pd_di->pd_evt_nh, nb);
- if (ret != 0)
- return ret;
-
- return ret;
-}
-EXPORT_SYMBOL(register_pd_dpm_notifier);
-
-int unregister_pd_dpm_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&g_pd_di->pd_evt_nh, nb);
-}
-EXPORT_SYMBOL(unregister_pd_dpm_notifier);
-
-static inline void pd_dpm_report_device_attach(void)
-{
- hisilog_info("%s \r\n", __func__);
- if (pd_dpm_get_pd_finish_flag()) {
- hisilog_info("%s, in pd process, report charger connect event\n",
- __func__);
- hisi_usb_otg_event(CHARGER_CONNECT_EVENT);
- }
-}
-
-static inline void pd_dpm_report_host_attach(void)
-{
- hisilog_info("%s \r\n", __func__);
-}
-
-static inline void pd_dpm_report_device_detach(void)
-{
- hisilog_info("%s \r\n", __func__);
- if (pd_dpm_get_pd_finish_flag()) {
- hisilog_info("%s, in pd process, report charger connect event\n",
- __func__);
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- }
- pd_dpm_vbus_notifier_call(g_pd_di, CHARGER_TYPE_NONE, NULL);
-}
-
-static inline void pd_dpm_report_host_detach(void)
-{
- hisilog_info("%s \r\n", __func__);
-}
-
-static void pd_dpm_report_attach(int new_state)
-{
- switch (new_state) {
- case PD_DPM_USB_TYPEC_DEVICE_ATTACHED:
- pd_dpm_report_device_attach();
- break;
-
- case PD_DPM_USB_TYPEC_HOST_ATTACHED:
- pd_dpm_report_host_attach();
- break;
- }
-}
-
-static void pd_dpm_report_detach(int last_state)
-{
- switch (last_state) {
- case PD_DPM_USB_TYPEC_DEVICE_ATTACHED:
- pd_dpm_report_device_detach();
- break;
-
- case PD_DPM_USB_TYPEC_HOST_ATTACHED:
- pd_dpm_report_host_detach();
- break;
- }
-}
-
-static void pd_dpm_usb_update_state(
- struct work_struct *work)
-{
- int new_ev, last_ev;
- struct pd_dpm_info *usb_cb_data =
- container_of(to_delayed_work(work),
- struct pd_dpm_info,
- usb_state_update_work);
-
- mutex_lock(&usb_cb_data->usb_lock);
- new_ev = usb_cb_data->pending_usb_event;
- mutex_unlock(&usb_cb_data->usb_lock);
-
- last_ev = usb_cb_data->last_usb_event;
-
- if (last_ev == new_ev)
- return;
-
- switch (new_ev) {
- case PD_DPM_USB_TYPEC_DETACHED:
- pd_dpm_report_detach(last_ev);
- break;
-
- case PD_DPM_USB_TYPEC_DEVICE_ATTACHED:
- case PD_DPM_USB_TYPEC_HOST_ATTACHED:
- if (last_ev != PD_DPM_USB_TYPEC_DETACHED)
- pd_dpm_report_detach(last_ev);
- pd_dpm_report_attach(new_ev);
- break;
- default:
- return;
- }
-
- usb_cb_data->last_usb_event = new_ev;
-}
-
-int pd_dpm_handle_pe_event(unsigned long event, void *data)
-{
- bool attach_event = false;
- int usb_event = PD_DPM_USB_TYPEC_NONE;
- struct pd_dpm_typec_state *typec_state = NULL;
-
- hisilog_err("%s:!!!,event=%ld,+++\n",
- __func__, event);
-
- switch (event) {
- case PD_DPM_PE_EVT_TYPEC_STATE:
- {
- typec_state = data;
- switch (typec_state->new_state) {
- case PD_DPM_TYPEC_ATTACHED_SNK:
- attach_event = true;
- usb_event = PD_DPM_USB_TYPEC_DEVICE_ATTACHED;
- break;
-
- case PD_DPM_TYPEC_ATTACHED_SRC:
- attach_event = true;
- usb_event = PD_DPM_USB_TYPEC_HOST_ATTACHED;
- break;
-
- case PD_DPM_TYPEC_UNATTACHED:
- mutex_lock(&g_pd_di->sink_vbus_lock);
- g_pd_di->pd_finish_flag = false;
- g_pd_di->bc12_finish_flag = false;
- g_pd_di->pd_source_vbus = false;
- mutex_unlock(&g_pd_di->sink_vbus_lock);
- usb_event = PD_DPM_USB_TYPEC_DETACHED;
- break;
-
- default:
- hisilog_info("%s can not detect typec state\r\n",
- __func__);
- break;
- }
- pd_dpm_set_typec_state(usb_event);
- }
- break;
-
- case PD_DPM_PE_EVT_PD_STATE:
- {
- struct pd_dpm_pd_state *pd_state = data;
-
- switch (pd_state->connected) {
- case PD_CONNECT_PE_READY_SNK:
- case PD_CONNECT_PE_READY_SRC:
- break;
- }
- }
- break;
-
- case PD_DPM_PE_EVT_DIS_VBUS_CTRL:
- {
- if (!g_pd_di) {
- hisilog_err("%s: g_pd_di is null!!!,+++\n",
- __func__);
- return -1;
- }
-
- if (g_pd_di->pd_finish_flag) {
- struct pd_dpm_vbus_state vbus_state;
-
- hisilog_info("%s : Disable VBUS Control\n",
- __func__);
- vbus_state.mv = 0;
- vbus_state.ma = 0;
-
- pd_dpm_vbus_notifier_call(g_pd_di,
- CHARGER_TYPE_NONE,
- &vbus_state);
- }
- }
- break;
-
- case PD_DPM_PE_EVT_SINK_VBUS:
- {
- pd_dpm_report_pd_sink_vbus(g_pd_di, data);
- }
- break;
-
- case PD_DPM_PE_EVT_SOURCE_VBUS:
- {
- pd_dpm_report_pd_source_vbus(g_pd_di, data);
- }
- break;
-
- case PD_DPM_PE_EVT_DR_SWAP:
- {
- struct pd_dpm_swap_state *swap_state = data;
-
- if (swap_state->new_role == PD_ROLE_DFP)
- usb_event = PD_DPM_USB_TYPEC_HOST_ATTACHED;
- else
- usb_event = PD_DPM_USB_TYPEC_DEVICE_ATTACHED;
- }
- break;
-
- case PD_DPM_PE_EVT_PR_SWAP:
- break;
-
- default:
- hisilog_info("%s unkonw event \r\n", __func__);
- break;
- };
-
- if (attach_event)
- pd_dpm_set_cc_orientation(typec_state->polarity);
-
- if (usb_event != PD_DPM_USB_TYPEC_NONE) {
- mutex_lock(&g_pd_di->usb_lock);
- if (g_pd_di->pending_usb_event != usb_event) {
- cancel_delayed_work(&g_pd_di->usb_state_update_work);
- g_pd_di->pending_usb_event = usb_event;
- queue_delayed_work(g_pd_di->usb_wq,
- &g_pd_di->usb_state_update_work,
- msecs_to_jiffies(0));
- } else {
- pr_info("Pending event is same --> ignore this event %d\n",
- usb_event);
- }
- mutex_unlock(&g_pd_di->usb_lock);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(pd_dpm_handle_pe_event);
-
-static int pd_dpm_parse_dt(struct pd_dpm_info *info,
- struct device *dev)
-{
- struct device_node *np = dev->of_node;
-
- if (!np)
- return -EINVAL;
- /* default name */
- if (of_property_read_string(np, "tcp_name",
- &info->tcpc_name) < 0)
- info->tcpc_name = "type_c_port0";
-
- return 0;
-}
-
-static int pd_dpm_probe(struct platform_device *pdev)
-{
- int ret = 0;
- struct pd_dpm_info *di;
-
- di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
- di->dev = &pdev->dev;
- hisilog_info("%s : +++++++++\n", __func__);
- g_pd_di = di;
-
- mutex_init(&di->sink_vbus_lock);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&di->pd_evt_nh);
- ATOMIC_INIT_NOTIFIER_HEAD(&di->pd_wake_unlock_evt_nh);
-
- di->usb_nb.notifier_call = pd_dpm_report_bc12;
- ret = hisi_charger_type_notifier_register(&di->usb_nb);
- if (ret < 0)
- hisilog_err("hisi_charger_type_notifier_register failed\n");
-
- if (typec_class) {
- typec_dev = device_create(typec_class, NULL, 0, NULL, "typec");
- ret = sysfs_create_group(&typec_dev->kobj, &pd_dpm_attr_group);
- if (ret)
- hisilog_err("%s: typec sysfs group create error\n",
- __func__);
- }
-
- hisilog_info("%s ++++\r\n\r\n", __func__);
-
- di->last_usb_event = PD_DPM_USB_TYPEC_NONE;
- di->pending_usb_event = PD_DPM_USB_TYPEC_NONE;
-
- mutex_init(&di->usb_lock);
-
- di->usb_wq = create_workqueue("pd_dpm_usb_wq");
- INIT_DELAYED_WORK(&di->usb_state_update_work,
- pd_dpm_usb_update_state);
- platform_set_drvdata(pdev, di);
-
- pd_dpm_parse_dt(di, &pdev->dev);
- notify_tcp_dev_ready(di->tcpc_name);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(pd_dpm_probe);
-
-static const struct of_device_id pd_dpm_callback_match_table[] = {
- {.compatible = "hisilicon,pd_dpm",},
- {},
-};
-
-static struct platform_driver pd_dpm_callback_driver = {
- .probe = pd_dpm_probe,
- .remove = NULL,
- .driver = {
- .name = "hisilicon,pd_dpm",
- .owner = THIS_MODULE,
- .of_match_table = pd_dpm_callback_match_table,
- }
-};
-
-static int __init pd_dpm_init(void)
-{
- hisilog_info("%s\n", __func__);
- /*adjust the original product*/
- typec_class = class_create(THIS_MODULE, "hisi_typec");
- if (IS_ERR(typec_class)) {
- hisilog_err("%s: cannot create class\n", __func__);
- return PTR_ERR(typec_class);
- }
-
- return platform_driver_register(&pd_dpm_callback_driver);
-}
-
-static void __exit pd_dpm_exit(void)
-{
- platform_driver_unregister(&pd_dpm_callback_driver);
-}
-
-device_initcall(pd_dpm_init);
-module_exit(pd_dpm_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("hisilicon pd dpm");
-MODULE_AUTHOR("wangbinghui<wangbinghui@hisilicon.com>");
+++ /dev/null
-config TCPC_CLASS
- bool "TypeC Port Controller Device Class"
- help
- Say Y to enable
- Typec Port
- Controller Device
- Class
-
-config USB_POWER_DELIVERY
- bool "Support USB power delivery Function"
- default n
- help
- Say Y to enable
- USB
- Power Delivery
- support
-
-config TCPC_RT1711H
- bool "Richtek RT1711H TypeC port Controller Driver"
- depends on TCPC_CLASS
- default n
- help
- Say Y to enable
- Richtek RT1711H
- TypeC port Controller
- Driver
-
-config USB_PD_VBUS_STABLE_TOUT
- int "PD VBUS Stable Timeout"
- depends on USB_POWER_DELIVERY
- range 0 1000 # >= 0, <= 1000
- default 125
- help
- Setup a timeout value (ms)
- for
- VBUS change
- stable
-
-config USB_PD_VBUS_PRESENT_TOUT
- int "PD VBUS Present Timeout"
- depends on USB_POWER_DELIVERY
- range 0 1000 # >= 0, <= 1000
- default 20
- help
- Setup a timeout value (ms)
- for
- VBUS present
- stable
+++ /dev/null
-obj-$(CONFIG_DUAL_ROLE_USB_INTF) += tcpci_dual_role.o
-obj-$(CONFIG_TCPC_RT1711H) += tcpc_rt1711h.o
-obj-$(CONFIG_TCPC_CLASS) += tcpci_core.o tcpci_typec.o tcpci_alert.o tcpci_timer.o tcpm.o rt-regmap.o
-obj-$(CONFIG_USB_POWER_DELIVERY) += tcpci_event.o \
- pd_core.o pd_policy_engine.o pd_process_evt.o \
- pd_dpm_core.o \
- pd_process_evt_snk.o pd_process_evt_src.o pd_process_evt_vdm.o \
- pd_process_evt_drs.o pd_process_evt_prs.o pd_process_evt_vcs.o \
- pd_process_evt_dbg.o \
- pd_policy_engine_src.o pd_policy_engine_snk.o pd_policy_engine_ufp.o pd_policy_engine_vcs.o \
- pd_policy_engine_dfp.o pd_policy_engine_dr.o pd_policy_engine_drs.o pd_policy_engine_prs.o \
- pd_policy_engine_dbg.o
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Core Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-/* From DTS */
-
-static int pd_parse_pdata(pd_port_t *pd_port)
-{
- struct device_node *np;
- int ret = 0, i;
-
- pr_info("%s\n", __func__);
- np = of_find_node_by_name(pd_port->tcpc_dev->dev.of_node, "pd-data");
-
- if (np) {
- ret = of_property_read_u32(
- np, "pd,source-pdo-size",
- (u32 *)&pd_port->local_src_cap_default.nr);
- if (ret < 0)
- pr_err("%s get source pdo size fail\n", __func__);
-
- ret = of_property_read_u32_array(
- np, "pd,source-pdo-data",
- (u32 *)pd_port->local_src_cap_default.pdos,
- pd_port->local_src_cap_default.nr);
- if (ret < 0)
- pr_err("%s get source pdo data fail\n", __func__);
-
- pr_info("%s src pdo data =\n", __func__);
- for (i = 0; i < pd_port->local_src_cap_default.nr; i++) {
- pr_info("%s %d: 0x%08x\n", __func__, i,
- pd_port->local_src_cap_default.pdos[i]);
- }
-
- ret = of_property_read_u32(np, "pd,sink-pdo-size",
- (u32 *)&pd_port->local_snk_cap.nr);
- if (ret < 0)
- pr_err("%s get sink pdo size fail\n", __func__);
-
- ret = of_property_read_u32_array(
- np, "pd,sink-pdo-data",
- (u32 *)pd_port->local_snk_cap.pdos,
- pd_port->local_snk_cap.nr);
- if (ret < 0)
- pr_err("%s get sink pdo data fail\n", __func__);
-
- pr_info("%s snk pdo data =\n", __func__);
- for (i = 0; i < pd_port->local_snk_cap.nr; i++) {
- pr_info("%s %d: 0x%08x\n", __func__, i,
- pd_port->local_snk_cap.pdos[i]);
- }
-
- ret = of_property_read_u32(np, "pd,id-vdo-size",
- (u32 *)&pd_port->id_vdo_nr);
- if (ret < 0)
- pr_err("%s get id vdo size fail\n", __func__);
- ret = of_property_read_u32_array(
- np, "pd,id-vdo-data",
- (u32 *)pd_port->id_vdos, pd_port->id_vdo_nr);
- if (ret < 0)
- pr_err("%s get id vdo data fail\n", __func__);
-
- pr_info("%s id vdos data =\n", __func__);
- for (i = 0; i < pd_port->id_vdo_nr; i++)
- pr_info("%s %d: 0x%08x\n", __func__, i,
- pd_port->id_vdos[i]);
- }
-
- return 0;
-}
-
-#define DEFAULT_DP_ROLE_CAP (MODE_DP_SRC)
-#define DEFAULT_DP_FIRST_CONNECTED (DPSTS_DFP_D_CONNECTED)
-#define DEFAULT_DP_SECOND_CONNECTED (DPSTS_DFP_D_CONNECTED)
-
-static const struct {
- const char *prop_name;
- u32 val;
-} supported_dpm_caps[] = {
- {"local_dr_power", DPM_CAP_LOCAL_DR_POWER},
- {"local_dr_data", DPM_CAP_LOCAL_DR_DATA},
- {"local_ext_power", DPM_CAP_LOCAL_EXT_POWER},
- {"local_usb_comm", DPM_CAP_LOCAL_USB_COMM},
- {"local_usb_suspend", DPM_CAP_LOCAL_USB_SUSPEND},
- {"local_high_cap", DPM_CAP_LOCAL_HIGH_CAP},
- {"local_give_back", DPM_CAP_LOCAL_GIVE_BACK},
- {"local_no_suspend", DPM_CAP_LOCAL_NO_SUSPEND},
- {"local_vconn_supply", DPM_CAP_LOCAL_VCONN_SUPPLY},
-
- {"attemp_discover_cable_dfp", DPM_CAP_ATTEMP_DISCOVER_CABLE_DFP},
- {"attemp_enter_dp_mode", DPM_CAP_ATTEMP_ENTER_DP_MODE},
- {"attemp_discover_cable", DPM_CAP_ATTEMP_DISCOVER_CABLE},
- {"attemp_discover_id", DPM_CAP_ATTEMP_DISCOVER_ID},
-
- {"pr_reject_as_source", DPM_CAP_PR_SWAP_REJECT_AS_SRC},
- {"pr_reject_as_sink", DPM_CAP_PR_SWAP_REJECT_AS_SNK},
- {"pr_check_gp_source", DPM_CAP_PR_SWAP_CHECK_GP_SRC},
- {"pr_check_gp_sink", DPM_CAP_PR_SWAP_CHECK_GP_SNK},
-
- {"dr_reject_as_dfp", DPM_CAP_DR_SWAP_REJECT_AS_DFP},
- {"dr_reject_as_ufp", DPM_CAP_DR_SWAP_REJECT_AS_UFP},
-
- {"snk_prefer_low_voltage", DPM_CAP_SNK_PREFER_LOW_VOLTAGE},
- {"snk_ignore_mismatch_current", DPM_CAP_SNK_IGNORE_MISMATCH_CURRENT},
-};
-
-static void pd_core_power_flags_init(pd_port_t *pd_port)
-{
- u32 src_flag, snk_flag, val;
- struct device_node *np;
- int i;
- pd_port_power_caps *snk_cap = &pd_port->local_snk_cap;
- pd_port_power_caps *src_cap = &pd_port->local_src_cap_default;
-
- np = of_find_node_by_name(pd_port->tcpc_dev->dev.of_node, "dpm_caps");
-
- for (i = 0; i < ARRAY_SIZE(supported_dpm_caps); i++) {
- if (of_property_read_bool(np,
- supported_dpm_caps[i].prop_name))
- pd_port->dpm_caps |=
- supported_dpm_caps[i].val;
- pr_info("dpm_caps: %s\n",
- supported_dpm_caps[i].prop_name);
- }
-
- if (of_property_read_u32(np, "pr_check", &val) == 0)
- pd_port->dpm_caps |= DPM_CAP_PR_CHECK_PROP(val);
- else
- pr_err("%s get pr_check data fail\n", __func__);
-
- if (of_property_read_u32(np, "dr_check", &val) == 0)
- pd_port->dpm_caps |= DPM_CAP_DR_CHECK_PROP(val);
- else
- pr_err("%s get dr_check data fail\n", __func__);
-
- pr_info("dpm_caps = 0x%08x\n", pd_port->dpm_caps);
-
- src_flag = 0;
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER)
- src_flag |= PDO_FIXED_DUAL_ROLE;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA)
- src_flag |= PDO_FIXED_DATA_SWAP;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_EXT_POWER)
- src_flag |= PDO_FIXED_EXTERNAL;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_USB_COMM)
- src_flag |= PDO_FIXED_COMM_CAP;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_USB_SUSPEND)
- src_flag |= PDO_FIXED_SUSPEND;
-
- snk_flag = src_flag;
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_HIGH_CAP)
- snk_flag |= PDO_FIXED_HIGH_CAP;
-
- snk_cap->pdos[0] |= snk_flag;
- src_cap->pdos[0] |= src_flag;
-}
-
-int pd_core_init(struct tcpc_device *tcpc_dev)
-{
- int ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- mutex_init(&pd_port->pd_lock);
- pd_port->tcpc_dev = tcpc_dev;
-
- pd_port->pe_pd_state = PE_IDLE2;
- pd_port->pe_vdm_state = PE_IDLE2;
-
- pd_port->pd_connect_state = PD_CONNECT_NONE;
-
- ret = pd_parse_pdata(pd_port);
- if (ret)
- return ret;
-
- pd_port->svid_data_cnt = 0;
- pd_core_power_flags_init(pd_port);
-
- PE_INFO("%s\r\n", __func__);
- return 0;
-}
-
-void pd_extract_rdo_power(u32 rdo, u32 pdo,
- u32 *op_curr, u32 *max_curr)
-{
- u32 op_power, max_power, vmin;
-
- switch (pdo & PDO_TYPE_MASK) {
- case PDO_TYPE_FIXED:
- case PDO_TYPE_VARIABLE:
- *op_curr = RDO_FIXED_VAR_EXTRACT_OP_CURR(rdo);
- *max_curr = RDO_FIXED_VAR_EXTRACT_MAX_CURR(rdo);
- break;
-
- case PDO_TYPE_BATTERY: /* TODO:check it later !! */
- vmin = PDO_BATT_EXTRACT_MIN_VOLT(pdo);
- op_power = RDO_BATT_EXTRACT_OP_POWER(rdo);
- max_power = RDO_BATT_EXTRACT_MAX_POWER(rdo);
-
- *op_curr = op_power / vmin;
- *max_curr = max_power / vmin;
- break;
-
- default:
- *op_curr = *max_curr = 0;
- break;
- }
-}
-
-u32 pd_reset_pdo_power(u32 pdo, u32 imax)
-{
- u32 ioper;
-
- switch (pdo & PDO_TYPE_MASK) {
- case PDO_TYPE_FIXED:
- ioper = PDO_FIXED_EXTRACT_CURR(pdo);
- if (ioper > imax)
- return PDO_FIXED_RESET_CURR(pdo, imax);
- break;
-
- case PDO_TYPE_VARIABLE:
- ioper = PDO_VAR_EXTRACT_CURR(pdo);
- if (ioper > imax)
- return PDO_VAR_RESET_CURR(pdo, imax);
- break;
-
- case PDO_TYPE_BATTERY:
- /* TODO:check it later !! */
- PD_ERR("No Support\r\n");
- break;
- }
- return pdo;
-}
-
-void pd_extract_pdo_power(u32 pdo,
- u32 *vmin, u32 *vmax, u32 *ioper)
-{
- u32 pwatt;
-
- switch (pdo & PDO_TYPE_MASK) {
- case PDO_TYPE_FIXED:
- *ioper = PDO_FIXED_EXTRACT_CURR(pdo);
- *vmin = *vmax = PDO_FIXED_EXTRACT_VOLT(pdo);
- break;
-
- case PDO_TYPE_VARIABLE:
- *ioper = PDO_VAR_EXTRACT_CURR(pdo);
- *vmin = PDO_VAR_EXTRACT_MIN_VOLT(pdo);
- *vmax = PDO_VAR_EXTRACT_MAX_VOLT(pdo);
- break;
-
- case PDO_TYPE_BATTERY: /* TODO:check it later !! */
- *vmin = PDO_BATT_EXTRACT_MIN_VOLT(pdo);
- *vmax = PDO_BATT_EXTRACT_MAX_VOLT(pdo);
- pwatt = PDO_BATT_EXTRACT_OP_POWER(pdo);
- *ioper = pwatt / *vmin;
- break;
-
- default:
- *vmin = *vmax = *ioper = 0;
- }
-}
-
-u32 pd_extract_cable_curr(u32 vdo)
-{
- u32 cable_curr;
-
- switch (PD_VDO_CABLE_CURR(vdo)) {
- case CABLE_CURR_1A5:
- cable_curr = 1500;
- break;
- case CABLE_CURR_5A:
- cable_curr = 5000;
- break;
- default:
- case CABLE_CURR_3A:
- cable_curr = 3000;
- break;
- }
-
- return cable_curr;
-}
-
-void pd_reset_svid_data(pd_port_t *pd_port)
-{
- u8 i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- svid_data->exist = false;
- svid_data->remote_mode.mode_cnt = 0;
- svid_data->active_mode = 0;
- }
-}
-
-int pd_reset_protocol_layer(pd_port_t *pd_port)
-{
- int i = 0;
-
- pd_notify_pe_reset_protocol(pd_port);
-
- pd_port->explicit_contract = 0;
- pd_port->local_selected_cap = 0;
- pd_port->remote_selected_cap = 0;
- pd_port->during_swap = 0;
- pd_port->dpm_ack_immediately = 0;
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- pd_port->vconn_return = false;
-#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
-
- for (i = 0; i < PD_SOP_NR; i++) {
- pd_port->msg_id_tx[i] = 0;
- pd_port->msg_id_rx[i] = 0;
- pd_port->msg_id_rx_init[i] = false;
- }
-
- return 0;
-}
-
-int pd_set_rx_enable(pd_port_t *pd_port, u8 enable)
-{
- return tcpci_set_rx_enable(pd_port->tcpc_dev, enable);
-}
-
-int pd_enable_vbus_valid_detection(pd_port_t *pd_port, bool wait_valid)
-{
- PE_DBG("WaitVBUS=%d\r\n", wait_valid);
- pd_notify_pe_wait_vbus_once(pd_port,
- wait_valid ? PD_WAIT_VBUS_VALID_ONCE :
- PD_WAIT_VBUS_INVALID_ONCE);
- return 0;
-}
-
-int pd_enable_vbus_safe0v_detection(pd_port_t *pd_port)
-{
- PE_DBG("WaitVSafe0V\r\n");
- pd_notify_pe_wait_vbus_once(pd_port, PD_WAIT_VBUS_SAFE0V_ONCE);
- return 0;
-}
-
-int pd_enable_vbus_stable_detection(pd_port_t *pd_port)
-{
- PE_DBG("WaitVStable\r\n");
- pd_notify_pe_wait_vbus_once(pd_port, PD_WAIT_VBUS_STABLE_ONCE);
- return 0;
-}
-
-int pd_set_data_role(pd_port_t *pd_port, u8 dr)
-{
- pd_port->data_role = dr;
-
- tcpci_notify_role_swap(pd_port->tcpc_dev, TCP_NOTIFY_DR_SWAP, dr);
- return tcpci_set_msg_header(pd_port->tcpc_dev,
- pd_port->power_role, pd_port->data_role);
-}
-
-int pd_set_power_role(pd_port_t *pd_port, u8 pr)
-{
- int ret;
-
- pd_port->power_role = pr;
- ret = tcpci_set_msg_header(pd_port->tcpc_dev,
- pd_port->power_role, pd_port->data_role);
- if (ret)
- return ret;
-
- pd_notify_pe_pr_changed(pd_port);
-
- tcpci_notify_role_swap(pd_port->tcpc_dev, TCP_NOTIFY_PR_SWAP, pr);
- return ret;
-}
-
-int pd_init_role(pd_port_t *pd_port, u8 pr, u8 dr, bool vr)
-{
- pd_port->power_role = pr;
- pd_port->data_role = dr;
- pd_port->vconn_source = vr;
-
- return tcpci_set_msg_header(pd_port->tcpc_dev,
- pd_port->power_role, pd_port->data_role);
-}
-
-int pd_set_vconn(pd_port_t *pd_port, int enable)
-{
- pd_port->vconn_source = enable;
-
- tcpci_notify_role_swap(pd_port->tcpc_dev,
- TCP_NOTIFY_VCONN_SWAP, enable);
- return tcpci_set_vconn(pd_port->tcpc_dev, enable);
-}
-
-static inline int pd_reset_modal_operation(pd_port_t *pd_port)
-{
- u8 i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
-
- if (svid_data->active_mode) {
- svid_data->active_mode = 0;
- tcpci_exit_mode(pd_port->tcpc_dev, svid_data->svid);
- }
- }
-
- pd_port->modal_operation = false;
- return 0;
-}
-
-int pd_reset_local_hw(pd_port_t *pd_port)
-{
- pd_notify_pe_transit_to_default(pd_port);
- pd_unlock_msg_output(pd_port);
-
- pd_reset_pe_timer(pd_port);
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_HARDRESET);
-
- pd_port->explicit_contract = false;
- pd_port->pd_connected = false;
- pd_port->pe_ready = false;
- pd_port->dpm_ack_immediately = false;
-
- pd_reset_modal_operation(pd_port);
-
- pd_set_vconn(pd_port, false);
-
- if (pd_port->power_role == PD_ROLE_SINK) {
- pd_port->state_machine = PE_STATE_MACHINE_SINK;
- pd_set_data_role(pd_port, PD_ROLE_UFP);
- } else {
- pd_port->state_machine = PE_STATE_MACHINE_SOURCE;
- pd_set_data_role(pd_port, PD_ROLE_DFP);
- }
-
- pd_dpm_notify_pe_hardreset(pd_port);
- PE_DBG("reset_local_hw\r\n");
-
- return 0;
-}
-
-int pd_enable_bist_test_mode(pd_port_t *pd_port, bool en)
-{
- PE_DBG("bist_test_mode=%d\r\n", en);
- return tcpci_set_bist_test_mode(pd_port->tcpc_dev, en);
-}
-
-/* ---- Handle PD Message ----*/
-
-int pd_handle_soft_reset(pd_port_t *pd_port, u8 state_machine)
-{
- pd_port->state_machine = state_machine;
-
- pd_reset_protocol_layer(pd_port);
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_RECV_SRESET);
- return pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-/* ---- Send PD Message ----*/
-
-static int pd_send_message(pd_port_t *pd_port, u8 sop_type,
- u8 msg, u16 count, const u32 *data)
-{
- int ret;
- u16 msg_hdr;
- u8 type = PD_TX_STATE_WAIT_CRC_PD;
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- if (tcpc_dev->typec_attach_old == 0) {
- PE_DBG("[SendMsg] Unattached\r\n");
- return 0;
- }
-
- if (tcpc_dev->pd_hard_reset_event_pending) {
- PE_DBG("[SendMsg] HardReset Pending");
- return 0;
- }
-
- if (sop_type == TCPC_TX_SOP) {
- msg_hdr = PD_HEADER_SOP(msg, pd_port->power_role,
- pd_port->data_role,
- pd_port->msg_id_tx[sop_type], count);
- } else {
- msg_hdr = PD_HEADER_SOP_PRIME(
- msg, 0,
- pd_port->msg_id_tx[sop_type], count);
- }
-
- if ((count > 0) && (msg == PD_DATA_VENDOR_DEF))
- type = PD_TX_STATE_WAIT_CRC_VDM;
-
- pd_port->msg_id_tx[sop_type] = (pd_port->msg_id_tx[sop_type] + 1) % 8;
-
- pd_notify_pe_transmit_msg(pd_port, type);
- ret = tcpci_transmit(pd_port->tcpc_dev, sop_type, msg_hdr, data);
- if (ret < 0)
- PD_ERR("[SendMsg] Failed, %d\r\n", ret);
-
- return ret;
-}
-
-int pd_send_ctrl_msg(pd_port_t *pd_port, u8 sop_type, u8 msg)
-{
- return pd_send_message(pd_port, sop_type, msg, 0, NULL);
-}
-
-int pd_send_data_msg(pd_port_t *pd_port,
- u8 sop_type, u8 msg,
- u8 cnt, u32 *payload)
-{
- return pd_send_message(pd_port, sop_type, msg, cnt, payload);
-}
-
-int pd_send_soft_reset(pd_port_t *pd_port, u8 state_machine)
-{
- pd_port->state_machine = state_machine;
-
- pd_reset_protocol_layer(pd_port);
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_SEND_SRESET);
- return pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_SOFT_RESET);
-}
-
-int pd_send_hard_reset(pd_port_t *pd_port)
-{
- int ret;
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- PE_DBG("Send HARD Reset\r\n");
-
- pd_port->hard_reset_counter++;
- pd_notify_pe_send_hard_reset(pd_port);
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_SEND_HRESET);
- ret = tcpci_transmit(tcpc_dev, TCPC_TX_HARD_RESET, 0, NULL);
- if (ret)
- return ret;
-
-#ifdef CONFIG_USB_PD_IGNORE_HRESET_COMPLETE_TIMER
- if (!(tcpc_dev->tcpc_flags & TCPC_FLAGS_WAIT_HRESET_COMPLETE)) {
- pd_put_sent_hard_reset_event(tcpc_dev);
- return 0;
- }
-#endif
- return 0;
-}
-
-int pd_send_bist_mode2(pd_port_t *pd_port)
-{
- int ret = 0;
-
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_SEND_BIST);
-
-#ifdef CONFIG_USB_PD_TRANSMIT_BIST2
- TCPC_DBG("BIST_MODE_2\r\n");
- ret = tcpci_transmit(
- pd_port->tcpc_dev, TCPC_TX_BIST_MODE_2, 0, NULL);
-#else
- ret = tcpci_set_bist_carrier_mode(
- pd_port->tcpc_dev, 1 << 2);
-#endif
-
- return ret;
-}
-
-int pd_disable_bist_mode2(pd_port_t *pd_port)
-{
-#ifndef CONFIG_USB_PD_TRANSMIT_BIST2
- return tcpci_set_bist_carrier_mode(
- pd_port->tcpc_dev, 0);
-#else
- return 0;
-#endif
-}
-
-/* ---- Send / Reply VDM Command ----*/
-
-int pd_send_svdm_request(pd_port_t *pd_port,
- u8 sop_type, u16 svid, u8 vdm_cmd,
- u8 obj_pos, u8 cnt, u32 *data_obj)
-{
- int ret;
- u32 payload[VDO_MAX_SIZE];
- char buf[1024] = { 0 };
-
- if (cnt >= (VDO_MAX_SIZE - 1))
- snprintf(buf, sizeof(buf), "%d over the vdo max size\n", cnt);
-
- payload[0] = VDO_S(svid, CMDT_INIT, vdm_cmd, obj_pos);
- memcpy(&payload[1], data_obj, sizeof(u32) * cnt);
-
- ret = pd_send_data_msg(
- pd_port, sop_type,
- PD_DATA_VENDOR_DEF, 1 + cnt, payload);
-
- if (ret == 0 && (vdm_cmd != CMD_ATTENTION))
- pd_enable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
-
- return ret;
-}
-
-int pd_reply_svdm_request(pd_port_t *pd_port, pd_event_t *pd_event,
- u8 reply, u8 cnt, u32 *data_obj)
-{
- u32 vdo;
- u32 payload[VDO_MAX_SIZE];
- char buf[1024] = { 0 };
-
- if (cnt >= (VDO_MAX_SIZE - 1))
- snprintf(buf, sizeof(buf), "%d over the vdo max size\n", cnt);
-
- if (!pd_event->pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
-
- vdo = pd_event->pd_msg->payload[0];
- payload[0] = VDO_S(
- PD_VDO_VID(vdo), reply, PD_VDO_CMD(vdo), PD_VDO_OPOS(vdo));
-
- if (cnt > 0) {
- if (!data_obj)
- snprintf(buf, sizeof(buf), "the data_obj is NULL\n");
-
- memcpy(&payload[1], data_obj, sizeof(u32) * cnt);
- }
-
- return pd_send_data_msg(pd_port,
- TCPC_TX_SOP, PD_DATA_VENDOR_DEF, 1 + cnt, payload);
-}
-
-void pd_lock_msg_output(pd_port_t *pd_port)
-{
- if (pd_port->msg_output_lock)
- return;
- pd_port->msg_output_lock = true;
-}
-
-void pd_unlock_msg_output(pd_port_t *pd_port)
-{
- if (!pd_port->msg_output_lock)
- return;
- pd_port->msg_output_lock = false;
-}
-
-int pd_update_connect_state(pd_port_t *pd_port, u8 state)
-{
- if (pd_port->pd_connect_state == state)
- return 0;
-
- switch (state) {
- case PD_CONNECT_TYPEC_ONLY:
- if (pd_port->power_role == PD_ROLE_SOURCE) {
- state = PD_CONNECT_TYPEC_ONLY_SRC;
- } else {
- switch (pd_port->tcpc_dev->typec_remote_rp_level) {
- case TYPEC_CC_VOLT_SNK_DFT:
- state = PD_CONNECT_TYPEC_ONLY_SNK_DFT;
- break;
-
- case TYPEC_CC_VOLT_SNK_1_5:
- case TYPEC_CC_VOLT_SNK_3_0:
- state = PD_CONNECT_TYPEC_ONLY_SNK;
- break;
- }
- }
- break;
-
- case PD_CONNECT_PE_READY:
- state = pd_port->power_role == PD_ROLE_SOURCE ?
- PD_CONNECT_PE_READY_SRC : PD_CONNECT_PE_READY_SNK;
- break;
-
- case PD_CONNECT_NONE:
- break;
- }
-
- pd_port->pd_connect_state = state;
- return tcpci_notify_pd_state(pd_port->tcpc_dev, state);
-}
-
-void pd_update_dpm_request_state(pd_port_t *pd_port, u8 state)
-{
- /* TODO */
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * PD Device Policy Manager Core Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-#include "pd_dpm_prv.h"
-
-/* DPM Init */
-
-static void pd_dpm_update_pdos_flags(pd_port_t *pd_port, u32 pdo)
-{
- pd_port->dpm_flags &= ~DPM_FLAGS_RESET_PARTNER_MASK;
-
- /* Only update PDO flags if pdo's type is fixed */
- if ((pdo & PDO_TYPE_MASK) != PDO_TYPE_FIXED)
- return;
-
- if (pdo & PDO_FIXED_DUAL_ROLE)
- pd_port->dpm_flags |= DPM_FLAGS_PARTNER_DR_POWER;
-
- if (pdo & PDO_FIXED_DATA_SWAP)
- pd_port->dpm_flags |= DPM_FLAGS_PARTNER_DR_DATA;
-
- if (pdo & PDO_FIXED_EXTERNAL)
- pd_port->dpm_flags |= DPM_FLAGS_PARTNER_EXTPOWER;
-
- if (pdo & PDO_FIXED_COMM_CAP)
- pd_port->dpm_flags |= DPM_FLAGS_PARTNER_USB_COMM;
-}
-
-int pd_dpm_enable_vconn(pd_port_t *pd_port, bool en)
-{
- return pd_set_vconn(pd_port, en);
-}
-
-int pd_dpm_send_sink_caps(pd_port_t *pd_port)
-{
- pd_port_power_caps *snk_cap = &pd_port->local_snk_cap;
-
- return pd_send_data_msg(pd_port, TCPC_TX_SOP, PD_DATA_SINK_CAP,
- snk_cap->nr, snk_cap->pdos);
-}
-
-int pd_dpm_send_source_caps(pd_port_t *pd_port)
-{
- u8 i;
- u32 cable_curr = 3000;
-
- pd_port_power_caps *src_cap0 = &pd_port->local_src_cap_default;
- pd_port_power_caps *src_cap1 = &pd_port->local_src_cap;
-
- if (pd_port->power_cable_present) {
- cable_curr =
- pd_extract_cable_curr(
- pd_port->cable_vdos[VDO_INDEX_CABLE]);
- DPM_DBG("cable_limit: %dmA\r\n", cable_curr);
- }
-
- src_cap1->nr = src_cap0->nr;
- for (i = 0; i < src_cap0->nr; i++) {
- src_cap1->pdos[i] =
- pd_reset_pdo_power(src_cap0->pdos[i], cable_curr);
- }
-
- return pd_send_data_msg(pd_port, TCPC_TX_SOP, PD_DATA_SOURCE_CAP,
- src_cap1->nr, src_cap1->pdos);
-}
-
-enum {
- GOOD_PW_NONE = 0, /* both no GP */
- GOOD_PW_PARTNER, /* partner has GP */
- GOOD_PW_LOCAL, /* local has GP */
- GOOD_PW_BOTH, /* both have GPs */
-};
-
-static inline int dpm_check_good_power(pd_port_t *pd_port)
-{
- bool local_ex, partner_ex;
-
- local_ex =
- (pd_port->dpm_caps & DPM_CAP_LOCAL_EXT_POWER) != 0;
-
- partner_ex =
- (pd_port->dpm_flags & DPM_FLAGS_PARTNER_EXTPOWER) != 0;
-
- if (local_ex != partner_ex) {
- if (partner_ex)
- return GOOD_PW_PARTNER;
- return GOOD_PW_LOCAL;
- }
-
- if (local_ex)
- return GOOD_PW_BOTH;
-
- return GOOD_PW_NONE;
-}
-
-static inline bool dpm_response_request(pd_port_t *pd_port, bool accept)
-{
- if (accept)
- return pd_put_dpm_ack_event(pd_port);
- return pd_put_dpm_nak_event(pd_port, PD_DPM_NAK_REJECT);
-}
-
-/* ---- SNK ---- */
-
-struct dpm_pdo_info_t {
- u8 type;
- int vmin;
- int vmax;
- int uw;
- int ma;
-};
-
-struct dpm_rdo_info_t {
- u8 pos;
- u8 type;
- bool mismatch;
-
- int vmin;
- int vmax;
-
- union {
- u32 max_uw;
- u32 max_ma;
- };
-
- union {
- u32 oper_uw;
- u32 oper_ma;
- };
-};
-
-#define DPM_PDO_TYPE_FIXED 0
-#define DPM_PDO_TYPE_BAT 1
-#define DPM_PDO_TYPE_VAR 2
-#define DPM_PDO_TYPE(pdo) (((pdo) & PDO_TYPE_MASK) >> 30)
-
-static inline bool dpm_is_valid_pdo_pair(
- struct dpm_pdo_info_t *sink,
- struct dpm_pdo_info_t *source, u32 caps)
-{
- if (sink->vmax < source->vmax)
- return false;
-
- if (sink->vmin > source->vmin)
- return false;
-
- if (caps & DPM_CAP_SNK_IGNORE_MISMATCH_CURRENT)
- return (sink->ma <= source->ma);
-
- return true;
-}
-
-static inline void dpm_extract_pdo_info(
- u32 pdo, struct dpm_pdo_info_t *info)
-{
- memset(info, 0, sizeof(struct dpm_pdo_info_t));
-
- info->type = DPM_PDO_TYPE(pdo);
-
- switch (info->type) {
- case DPM_PDO_TYPE_FIXED:
- info->ma = PDO_FIXED_EXTRACT_CURR(pdo);
- info->vmin = PDO_FIXED_EXTRACT_VOLT(pdo);
- info->vmax = info->vmin;
- info->uw = info->ma * info->vmax;
- break;
-
- case DPM_PDO_TYPE_VAR:
- info->ma = PDO_VAR_OP_CURR(pdo);
- info->vmin = PDO_VAR_EXTRACT_MIN_VOLT(pdo);
- info->vmax = PDO_VAR_EXTRACT_MAX_VOLT(pdo);
- info->uw = info->ma * info->vmax;
- break;
-
- case DPM_PDO_TYPE_BAT:
- info->uw = PDO_BATT_EXTRACT_OP_POWER(pdo) * 1000;
- info->vmin = PDO_BATT_EXTRACT_MIN_VOLT(pdo);
- info->vmax = PDO_BATT_EXTRACT_MAX_VOLT(pdo);
- info->ma = info->uw / info->vmin;
- break;
- }
-}
-
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-static inline int dpm_calc_src_cap_power_uw(
- struct dpm_pdo_info_t *source, struct dpm_pdo_info_t *sink)
-{
- int uw, ma;
-
- if (source->type == DPM_PDO_TYPE_BAT) {
- uw = source->uw;
-
- if (sink->type == DPM_PDO_TYPE_BAT)
- uw = MIN(uw, sink->uw);
- } else {
- ma = source->ma;
-
- if (sink->type != DPM_PDO_TYPE_BAT)
- ma = MIN(ma, sink->ma);
-
- uw = ma * source->vmax;
- }
-
- return uw;
-}
-
-static bool dpm_find_match_req_info(
- struct dpm_rdo_info_t *req_info,
- u32 snk_pdo, int cnt, u32 *src_pdos,
- int min_uw, u32 caps)
-{
- bool overload;
- int ret = -1;
- int i;
- int uw, max_uw = min_uw, cur_mv = 0;
- struct dpm_pdo_info_t sink, source;
-
- dpm_extract_pdo_info(snk_pdo, &sink);
-
- for (i = 0; i < cnt; i++) {
- dpm_extract_pdo_info(src_pdos[i], &source);
- if (!dpm_is_valid_pdo_pair(&sink, &source, caps))
- continue;
-
- uw = dpm_calc_src_cap_power_uw(&source, &sink);
-
- overload = uw > max_uw;
-
- if (caps & DPM_CAP_SNK_PREFER_LOW_VOLTAGE)
- overload |= (uw == max_uw) && (source.vmax < cur_mv);
-
- if (overload) {
- ret = i;
- max_uw = uw;
- cur_mv = source.vmax;
- }
- }
-
- if (ret >= 0) {
- req_info->pos = ret + 1;
- req_info->type = source.type;
-
- dpm_extract_pdo_info(src_pdos[ret], &source);
-
- req_info->vmax = source.vmax;
- req_info->vmin = source.vmin;
-
- if (sink.type == DPM_PDO_TYPE_BAT)
- req_info->mismatch = max_uw < sink.uw;
- else
- req_info->mismatch = source.ma < sink.ma;
-
- if (source.type == DPM_PDO_TYPE_BAT) {
- req_info->max_uw = sink.uw;
- req_info->oper_uw = max_uw;
- } else {
- req_info->max_ma = sink.ma;
- req_info->oper_ma = MIN(sink.ma, source.ma);
- }
- }
-
- return (ret >= 0);
-}
-
-static bool dpm_build_request_info(
- pd_port_t *pd_port, struct dpm_rdo_info_t *req_info)
-{
- bool find_cap = false;
- int i, max_uw = 0;
- pd_port_power_caps *snk_cap = &pd_port->local_snk_cap;
- pd_port_power_caps *src_cap = &pd_port->remote_src_cap;
-
- memset(req_info, 0, sizeof(struct dpm_rdo_info_t));
-
- for (i = 0; i < src_cap->nr; i++)
- DPM_DBG("SrcCap%d: 0x%08x\r\n", i + 1, src_cap->pdos[i]);
-
- for (i = 0; i < snk_cap->nr; i++) {
- DPM_DBG("EvaSinkCap%d\r\n", i + 1);
-
- find_cap = dpm_find_match_req_info(
- req_info, snk_cap->pdos[i],
- src_cap->nr, src_cap->pdos,
- max_uw, pd_port->dpm_caps);
-
- if (find_cap) {
- if (req_info->type == DPM_PDO_TYPE_BAT)
- max_uw = req_info->oper_uw;
- else
- max_uw = req_info->vmax * req_info->oper_ma;
-
- DPM_DBG("Find SrcCap%d(%s):%d mw\r\n",
- req_info->pos, req_info->mismatch ?
- "Mismatch" : "Match", max_uw / 1000);
- pd_port->local_selected_cap = i + 1;
- }
- }
-
- return max_uw != 0;
-}
-
-static bool dpm_build_default_request_info(
- pd_port_t *pd_port, struct dpm_rdo_info_t *req_info)
-{
- struct dpm_pdo_info_t sink, source;
- pd_port_power_caps *snk_cap = &pd_port->local_snk_cap;
- pd_port_power_caps *src_cap = &pd_port->remote_src_cap;
-
- pd_port->local_selected_cap = 1;
-
- dpm_extract_pdo_info(snk_cap->pdos[0], &sink);
- dpm_extract_pdo_info(src_cap->pdos[0], &source);
-
- req_info->pos = 1;
- req_info->type = source.type;
- req_info->mismatch = true;
- req_info->vmax = 5000;
- req_info->vmin = 5000;
-
- if (req_info->type == DPM_PDO_TYPE_BAT) {
- req_info->max_uw = sink.uw;
- req_info->oper_uw = source.uw;
-
- } else {
- req_info->max_ma = sink.ma;
- req_info->oper_ma = source.ma;
- }
-
- return true;
-}
-
-static inline void dpm_update_request(
- pd_port_t *pd_port, struct dpm_rdo_info_t *req_info)
-{
- u32 mw_op, mw_max;
-
- u32 flags = 0;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_GIVE_BACK)
- flags |= RDO_GIVE_BACK;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_NO_SUSPEND)
- flags |= RDO_NO_SUSPEND;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_USB_COMM)
- flags |= RDO_COMM_CAP;
-
- if (req_info->mismatch)
- flags |= RDO_CAP_MISMATCH;
-
- pd_port->request_v_new = req_info->vmax;
-
- if (req_info->type == DPM_PDO_TYPE_BAT) {
- mw_op = req_info->oper_uw / 1000;
- mw_max = req_info->max_uw / 1000;
-
- pd_port->request_i_op = req_info->oper_uw / req_info->vmin;
- pd_port->request_i_max = req_info->max_uw / req_info->vmin;
-
- if (req_info->mismatch)
- pd_port->request_i_new = pd_port->request_i_op;
- else
- pd_port->request_i_new = pd_port->request_i_max;
-
- pd_port->last_rdo = RDO_BATT(
- req_info->pos, mw_op, mw_max, flags);
- } else {
- pd_port->request_i_op = req_info->oper_ma;
- pd_port->request_i_max = req_info->max_ma;
-
- if (req_info->mismatch)
- pd_port->request_i_new = pd_port->request_i_op;
- else
- pd_port->request_i_new = pd_port->request_i_max;
-
- pd_port->last_rdo = RDO_FIXED(
- req_info->pos, req_info->oper_ma,
- req_info->max_ma, flags);
- }
-}
-
-bool pd_dpm_send_request(pd_port_t *pd_port, int mv, int ma)
-{
- bool find_cap = false;
- struct dpm_rdo_info_t req_info;
- pd_port_power_caps *src_cap = &pd_port->remote_src_cap;
- u32 snk_pdo = PDO_FIXED(mv, ma, 0);
-
- memset(&req_info, 0, sizeof(struct dpm_rdo_info_t));
-
- find_cap = dpm_find_match_req_info(
- &req_info, snk_pdo,
- src_cap->nr, src_cap->pdos,
- 0, pd_port->dpm_caps);
-
- if (!find_cap)
- return false;
-
- dpm_update_request(pd_port, &req_info);
- return pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_PW_REQUEST);
-}
-
-void pd_dpm_snk_evaluate_caps(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool find_cap = false;
- int sink_nr, source_nr;
- char buf[1024] = { 0 };
-
- struct dpm_rdo_info_t req_info;
- pd_msg_t *pd_msg = pd_event->pd_msg;
- pd_port_power_caps *snk_cap = &pd_port->local_snk_cap;
- pd_port_power_caps *src_cap = &pd_port->remote_src_cap;
-
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
-
- sink_nr = snk_cap->nr;
- source_nr = PD_HEADER_CNT(pd_msg->msg_hdr);
-
- if ((source_nr <= 0) || (sink_nr <= 0)) {
- DPM_DBG("SrcNR or SnkNR = 0\r\n");
- return;
- }
-
- src_cap->nr = source_nr;
- memcpy(src_cap->pdos, pd_msg->payload, sizeof(u32) * source_nr);
- pd_dpm_update_pdos_flags(pd_port, src_cap->pdos[0]);
-
- find_cap = dpm_build_request_info(pd_port, &req_info);
-
- /* If we can't find any cap to use, choose default setting */
- if (!find_cap) {
- DPM_DBG("Can't find any SrcCap\r\n");
- dpm_build_default_request_info(pd_port, &req_info);
- }
-
- dpm_update_request(pd_port, &req_info);
-
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SOURCE_CAP;
- if (!(pd_port->dpm_flags & DPM_FLAGS_PARTNER_DR_POWER))
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SINK_CAP;
-
- if (req_info.pos > 0)
- pd_put_dpm_notify_event(pd_port, req_info.pos);
-}
-
-void pd_dpm_snk_transition_power(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- tcpci_sink_vbus(
- pd_port->tcpc_dev, TCP_VBUS_CTRL_REQUEST,
- pd_port->request_v_new,
- pd_port->request_i_new);
-
- pd_port->request_v = pd_port->request_v_new;
- pd_port->request_i = pd_port->request_i_new;
-}
-
-void pd_dpm_snk_hard_reset(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- tcpci_sink_vbus(
- pd_port->tcpc_dev,
- TCP_VBUS_CTRL_HRESET,
- TCPC_VBUS_SINK_0V, 0);
- pd_put_pe_event(pd_port, PD_PE_POWER_ROLE_AT_DEFAULT);
-}
-
-/* ---- SRC ---- */
-
-void pd_dpm_src_evaluate_request(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u8 rdo_pos;
- u32 rdo, pdo;
- u32 op_curr, max_curr;
- u32 source_vmin, source_vmax, source_i;
- bool accept_request = true;
- char buf[1024] = { 0 };
-
- pd_msg_t *pd_msg = pd_event->pd_msg;
- pd_port_power_caps *src_cap = &pd_port->local_src_cap;
-
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
-
- rdo = pd_msg->payload[0];
- rdo_pos = RDO_POS(rdo);
-
- DPM_DBG("RequestCap%d\r\n", rdo_pos);
-
- pd_port->dpm_flags &= (~DPM_FLAGS_PARTNER_MISMATCH);
- if ((rdo_pos > 0) && (rdo_pos <= src_cap->nr)) {
- pdo = src_cap->pdos[rdo_pos - 1];
-
- pd_extract_rdo_power(rdo, pdo, &op_curr, &max_curr);
- pd_extract_pdo_power(
- pdo, &source_vmin,
- &source_vmax, &source_i);
-
- if (source_i < op_curr) {
- DPM_DBG("src_i (%d) < op_i (%d)\r\n",
- source_i, op_curr);
- accept_request = false;
- }
-
- if (rdo & RDO_CAP_MISMATCH) {
- /* TODO: handle it later */
- DPM_DBG("CAP_MISMATCH\r\n");
- pd_port->dpm_flags |= DPM_FLAGS_PARTNER_MISMATCH;
- } else if (source_i < max_curr) {
- DPM_DBG("src_i (%d) < max_i (%d)\r\n",
- source_i, max_curr);
- accept_request = false;
- }
- } else {
- accept_request = false;
- DPM_DBG("RequestPos Wrong (%d)\r\n", rdo_pos);
- }
-
- if (accept_request) {
- pd_port->local_selected_cap = rdo_pos;
-
- pd_port->request_i_op = op_curr;
- pd_port->request_i_max = max_curr;
-
- if (rdo & RDO_CAP_MISMATCH)
- pd_port->request_i_new = op_curr;
- else
- pd_port->request_i_new = max_curr;
-
- pd_port->request_v_new = source_vmin;
- pd_put_dpm_notify_event(pd_port, rdo_pos);
- } else {
- /*
- * "Contract Invalid" means that the previously
- * negotiated Voltage and Current values
- * are no longer included in the Sources new Capabilities.
- * If the Sink fails to make a valid Request in this case
- * then Power Delivery operation is no longer possible
- * and Power Delivery mode is exited with a Hard Reset.
- */
-
- pd_port->local_selected_cap = 0;
- pd_put_dpm_nak_event(pd_port, PD_DPM_NAK_REJECT_INVALID);
- }
-}
-
-void pd_dpm_src_transition_power(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_vbus_stable_detection(pd_port);
-
- tcpci_source_vbus(
- pd_port->tcpc_dev, TCP_VBUS_CTRL_REQUEST,
- pd_port->request_v_new, pd_port->request_i_new);
-
- if (pd_port->request_v == pd_port->request_v_new)
- pd_put_vbus_stable_event(pd_port->tcpc_dev);
-#if CONFIG_USB_PD_VBUS_STABLE_TOUT
- else
- pd_enable_timer(pd_port, PD_TIMER_VBUS_STABLE);
-#endif /* CONFIG_USB_PD_VBUS_STABLE_TOUT */
-
- pd_port->request_v = pd_port->request_v_new;
- pd_port->request_i = pd_port->request_i_new;
-}
-
-void pd_dpm_src_inform_cable_vdo(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- const int size = sizeof(u32) * VDO_MAX_SIZE;
-
- if (pd_event->pd_msg)
- memcpy(pd_port->cable_vdos, pd_event->pd_msg->payload, size);
-
- pd_put_dpm_ack_event(pd_port);
-}
-
-void pd_dpm_src_hard_reset(pd_port_t *pd_port)
-{
- tcpci_source_vbus(
- pd_port->tcpc_dev,
- TCP_VBUS_CTRL_HRESET,
- TCPC_VBUS_SOURCE_0V, 0);
- pd_enable_vbus_safe0v_detection(pd_port);
-}
-
-/* ---- UFP : update_svid_data ---- */
-
-static inline bool dpm_ufp_update_svid_data_enter_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- svdm_svid_data_t *svid_data;
-
- DPM_DBG("EnterMode (svid0x%04x, ops:%d)\r\n", svid, ops);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
-
- if (!svid_data)
- return false;
-
- /* Only accept 1 mode active at the same time */
- if (svid_data->active_mode)
- return false;
-
- if ((ops == 0) || (ops > svid_data->local_mode.mode_cnt))
- return false;
-
- svid_data->active_mode = ops;
- pd_port->modal_operation = true;
-
- svdm_ufp_request_enter_mode(pd_port, svid, ops);
-
- tcpci_enter_mode(
- pd_port->tcpc_dev,
- svid, ops,
- svid_data->local_mode.mode_vdo[ops]);
- return true;
-}
-
-static inline bool dpm_ufp_update_svid_data_exit_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- u8 i;
- bool modal_operation;
- svdm_svid_data_t *svid_data;
-
- DPM_DBG("ExitMode (svid0x%04x, mode:%d)\r\n", svid, ops);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
-
- if (!svid_data)
- return false;
-
- if (svid_data->active_mode == 0)
- return false;
-
- if ((ops == 0) || (ops == svid_data->active_mode)) {
- svid_data->active_mode = 0;
-
- modal_operation = false;
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
-
- if (svid_data->active_mode) {
- modal_operation = true;
- break;
- }
- }
-
- pd_port->modal_operation = modal_operation;
-
- svdm_ufp_request_exit_mode(pd_port, svid, ops);
- tcpci_exit_mode(pd_port->tcpc_dev, svid);
- return true;
- }
-
- return false;
-}
-
-/* ---- UFP : Evaluate VDM Request ---- */
-
-static inline bool pd_dpm_ufp_reply_request(
- pd_port_t *pd_port, pd_event_t *pd_event, bool ack)
-{
- return vdm_put_dpm_event(
- pd_port, ack ? PD_DPM_ACK : PD_DPM_NAK, pd_event->pd_msg);
-}
-
-static inline u32 dpm_vdm_get_svid(pd_event_t *pd_event)
-{
- pd_msg_t *pd_msg = pd_event->pd_msg;
- char buf[1024] = { 0 };
-
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
- return PD_VDO_VID(pd_msg->payload[0]);
-}
-
-void pd_dpm_ufp_request_id_info(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_reply_request(
- pd_port, pd_event,
- dpm_vdm_get_svid(pd_event) == USB_SID_PD);
-}
-
-void pd_dpm_ufp_request_svid_info(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ack = false;
-
- if (pd_is_support_modal_operation(pd_port))
- ack = (dpm_vdm_get_svid(pd_event) == USB_SID_PD);
-
- pd_dpm_ufp_reply_request(pd_port, pd_event, ack);
-}
-
-void pd_dpm_ufp_request_mode_info(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u16 svid = dpm_vdm_get_svid(pd_event);
- bool ack = 0;
-
- if (dpm_get_svdm_svid_data(pd_port, svid))
- ack = 1;
- pd_dpm_ufp_reply_request(pd_port, pd_event, ack);
-}
-
-void pd_dpm_ufp_request_enter_mode(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ack = false;
- u16 svid;
- u8 ops;
- char buf[1024] = { 0 };
-
- if (!pd_event->pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
- dpm_vdm_get_svid_ops(pd_event, &svid, &ops);
- ack = dpm_ufp_update_svid_data_enter_mode(pd_port, svid, ops);
-
- pd_dpm_ufp_reply_request(pd_port, pd_event, ack);
-}
-
-void pd_dpm_ufp_request_exit_mode(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ack;
- u16 svid;
- u8 ops;
-
- dpm_vdm_get_svid_ops(pd_event, &svid, &ops);
- ack = dpm_ufp_update_svid_data_exit_mode(pd_port, svid, ops);
- pd_dpm_ufp_reply_request(pd_port, pd_event, ack);
-}
-
-/* ---- UFP : Response VDM Request ---- */
-
-int pd_dpm_ufp_response_id(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- return pd_reply_svdm_request(pd_port, pd_event,
- CMDT_RSP_ACK, pd_port->id_vdo_nr, pd_port->id_vdos);
-}
-
-int pd_dpm_ufp_response_svids(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- svdm_svid_data_t *svid_data;
- u16 svid_list[2];
- u32 svids[VDO_MAX_DATA_SIZE];
- u8 i = 0, j = 0, cnt = pd_port->svid_data_cnt;
- char buf[1024] = { 0 };
-
- if (pd_port->svid_data_cnt >= VDO_MAX_SVID_SIZE) {
- snprintf(buf, sizeof(buf),
- "the %d is over vdo max svid size\n",
- pd_port->svid_data_cnt);
- }
-
- if (unlikely(cnt >= VDO_MAX_SVID_SIZE))
- cnt = VDO_MAX_SVID_SIZE;
-
- while (i < cnt) {
- svid_data = &pd_port->svid_data[i++];
- svid_list[0] = svid_data->svid;
-
- if (i < cnt) {
- svid_data = &pd_port->svid_data[i++];
- svid_list[1] = svid_data->svid;
- } else {
- svid_list[1] = 0;
- }
- svids[j++] = VDO_SVID(svid_list[0], svid_list[1]);
- }
-
- if ((cnt % 2) == 0)
- svids[j++] = VDO_SVID(0, 0);
-
- return pd_reply_svdm_request(
- pd_port, pd_event, CMDT_RSP_ACK, j, svids);
-}
-
-int pd_dpm_ufp_response_modes(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- svdm_svid_data_t *svid_data;
- u16 svid = dpm_vdm_get_svid(pd_event);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (svid_data) {
- return pd_reply_svdm_request(
- pd_port, pd_event, CMDT_RSP_ACK,
- svid_data->local_mode.mode_cnt,
- svid_data->local_mode.mode_vdo);
- } else {
- PE_DBG("ERROR-4965\r\n");
- return pd_reply_svdm_request_simply(
- pd_port, pd_event, CMDT_RSP_NAK);
- }
-}
-
-/* ---- DFP : update_svid_data ---- */
-
-static inline void dpm_dfp_update_svid_data_exist(
- pd_port_t *pd_port, u16 svid)
-{
- u8 k;
- svdm_svid_data_t *svid_data;
-
-#ifdef CONFIG_USB_PD_KEEP_SVIDS
- svdm_svid_list_t *list = &pd_port->remote_svid_list;
-
- if (list->cnt < VDO_MAX_SVID_SIZE)
- list->svids[list->cnt++] = svid;
- else
- DPM_DBG("ERR:SVIDCNT\r\n");
-#endif
-
- for (k = 0; k < pd_port->svid_data_cnt; k++) {
- svid_data = &pd_port->svid_data[k];
-
- if (svid_data->svid == svid)
- svid_data->exist = 1;
- }
-}
-
-static inline void dpm_dfp_update_svid_data_modes(
- pd_port_t *pd_port, u16 svid, u32 *mode_list, u8 count)
-{
- u8 i;
- svdm_svid_data_t *svid_data;
-
- DPM_DBG("InformMode (0x%04x:%d): \r\n", svid, count);
- for (i = 0; i < count; i++)
- DPM_DBG("Mode[%d]: 0x%08x\r\n", i, mode_list[i]);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return;
-
- svid_data->remote_mode.mode_cnt = count;
-
- if (count != 0) {
- memcpy(svid_data->remote_mode.mode_vdo,
- mode_list, sizeof(u32) * count);
- }
-}
-
-static inline void dpm_dfp_update_svid_enter_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- svdm_svid_data_t *svid_data;
-
- DPM_DBG("EnterMode (svid0x%04x, mode:%d)\r\n", svid, ops);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return;
-
- svid_data->active_mode = ops;
- pd_port->modal_operation = true;
-
- tcpci_enter_mode(
- pd_port->tcpc_dev,
- svid_data->svid, ops,
- svid_data->remote_mode.mode_vdo[ops]);
-}
-
-static inline void dpm_dfp_update_svid_data_exit_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- u8 i;
- bool modal_operation;
- svdm_svid_data_t *svid_data;
-
- DPM_DBG("ExitMode (svid0x%04x, mode:%d)\r\n", svid, ops);
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return;
-
- if ((ops == 0) || (ops == svid_data->active_mode)) {
- svid_data->active_mode = 0;
-
- modal_operation = false;
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
-
- if (svid_data->active_mode) {
- modal_operation = true;
- break;
- }
- }
-
- pd_port->modal_operation = modal_operation;
- tcpci_exit_mode(pd_port->tcpc_dev, svid);
- }
-}
-
-/* ---- DFP : Inform VDM Result ---- */
-
-void pd_dpm_dfp_inform_id(pd_port_t *pd_port, pd_event_t *pd_event, bool ack)
-{
-#if DPM_DBG_ENABLE
- pd_msg_t *pd_msg = pd_event->pd_msg;
-#endif /* DPM_DBG_ENABLE */
-
- if (ack) {
- DPM_DBG("InformID, 0x%02x, 0x%02x, 0x%02x, 0x%02x\r\n",
- pd_msg->payload[0], pd_msg->payload[1],
- pd_msg->payload[2], pd_msg->payload[3]);
- }
-
- svdm_dfp_inform_id(pd_port, pd_event, ack);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-static inline int dpm_dfp_consume_svids(
- pd_port_t *pd_port, u32 *svid_list, u8 count)
-{
- bool discover_again = true;
-
- u8 i, j;
- u16 svid[2];
-
- DPM_DBG("InformSVID (%d): \r\n", count);
-
- if (count < 6)
- discover_again = false;
-
- for (i = 0; i < count; i++) {
- svid[0] = PD_VDO_SVID_SVID0(svid_list[i]);
- svid[1] = PD_VDO_SVID_SVID1(svid_list[i]);
-
- DPM_DBG("svid[%d]: 0x%04x 0x%04x\r\n", i, svid[0], svid[1]);
-
- for (j = 0; j < 2; j++) {
- if (svid[j] == 0) {
- discover_again = false;
- break;
- }
-
- dpm_dfp_update_svid_data_exist(pd_port, svid[j]);
- }
- }
-
- if (discover_again) {
- DPM_DBG("DiscoverSVID Again\r\n");
- vdm_put_dpm_vdm_request_event(
- pd_port, PD_DPM_VDM_REQUEST_DISCOVER_SVIDS);
- return 1;
- }
-
- return 0;
-}
-
-void pd_dpm_dfp_inform_svids(pd_port_t *pd_port, pd_event_t *pd_event, bool ack)
-{
- u8 count;
- u32 *svid_list;
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- if (ack) {
- svid_list = &pd_msg->payload[1];
- count = (PD_HEADER_CNT(pd_msg->msg_hdr) - 1);
-
- if (dpm_dfp_consume_svids(pd_port, svid_list, count))
- return;
- }
-
- svdm_dfp_inform_svids(pd_port, ack);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-void pd_dpm_dfp_inform_modes(
- pd_port_t *pd_port, pd_event_t *pd_event, bool ack)
-{
- u8 count;
- u16 svid = 0;
- u16 expected_svid = pd_port->mode_svid;
-
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- if (ack) {
- count = (PD_HEADER_CNT(pd_msg->msg_hdr));
- svid = PD_VDO_VID(pd_msg->payload[VDO_INDEX_HDR]);
-
- if (svid != expected_svid) {
- ack = false;
- DPM_DBG("Not expected SVID (0x%04x, 0x%04x)\r\n",
- svid, expected_svid);
- } else {
- dpm_dfp_update_svid_data_modes(
- pd_port, svid, &pd_msg->payload[1], count - 1);
- }
- }
-
- svdm_dfp_inform_modes(pd_port, expected_svid, ack);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-void pd_dpm_dfp_inform_enter_mode(
- pd_port_t *pd_port,
- pd_event_t *pd_event, bool ack)
-{
- u16 svid = 0;
- u16 expected_svid = pd_port->mode_svid;
- u8 ops = 0;
-
- if (ack) {
- dpm_vdm_get_svid_ops(pd_event, &svid, &ops);
-
- /* TODO: check ops later ?! */
- if (svid != expected_svid) {
- ack = false;
- DPM_DBG("Not expected SVID (0x%04x, 0x%04x)\r\n",
- svid, expected_svid);
- } else {
- dpm_dfp_update_svid_enter_mode(pd_port, svid, ops);
- }
- }
-
- svdm_dfp_inform_enter_mode(pd_port, expected_svid, ops, ack);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-void pd_dpm_dfp_inform_exit_mode(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u16 svid = 0;
- u16 expected_svid = pd_port->mode_svid;
- u8 ops;
-
- if (pd_event->event_type != PD_EVT_TIMER_MSG) {
- dpm_vdm_get_svid_ops(pd_event, &svid, &ops);
- } else {
- svid = pd_port->mode_svid;
- ops = pd_port->mode_obj_pos;
- }
-
- dpm_dfp_update_svid_data_exit_mode(pd_port, expected_svid, ops);
-
- svdm_dfp_inform_exit_mode(pd_port, expected_svid, ops);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-void pd_dpm_dfp_inform_attention(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u16 svid = 0;
- u8 ops;
-
- dpm_vdm_get_svid_ops(pd_event, &svid, &ops);
- DPM_DBG("Attention (svid0x%04x, mode:%d)\r\n", svid, ops);
-
- svdm_dfp_inform_attention(pd_port, svid, pd_event);
- vdm_put_dpm_notified_event(pd_port);
-}
-
-void pd_dpm_dfp_inform_cable_vdo(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- const int size = sizeof(u32) * VDO_MAX_SIZE;
-
- if (pd_event->pd_msg)
- memcpy(pd_port->cable_vdos, pd_event->pd_msg->payload, size);
-
- vdm_put_dpm_notified_event(pd_port);
-}
-
-/*
- * DRP : Inform Source/Sink Cap
- */
-
-void pd_dpm_dr_inform_sink_cap(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_msg_t *pd_msg = pd_event->pd_msg;
- pd_port_power_caps *snk_cap = &pd_port->remote_snk_cap;
- char buf[1024] = { 0 };
-
- if (pd_event_msg_match(pd_event, PD_EVT_DATA_MSG, PD_DATA_SINK_CAP)) {
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
- snk_cap->nr = PD_HEADER_CNT(pd_msg->msg_hdr);
- memcpy(snk_cap->pdos, pd_msg->payload,
- sizeof(u32) * snk_cap->nr);
-
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SINK_CAP;
- } else {
- if (pd_event_msg_match(
- pd_event,
- PD_EVT_CTRL_MSG,
- PD_CTRL_REJECT))
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SINK_CAP;
-
- snk_cap->nr = 0;
- snk_cap->pdos[0] = 0;
- }
-
- pd_dpm_update_pdos_flags(pd_port, snk_cap->pdos[0]);
-}
-
-void pd_dpm_dr_inform_source_cap(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_msg_t *pd_msg = pd_event->pd_msg;
- pd_port_power_caps *src_cap = &pd_port->remote_src_cap;
- char buf[1024] = { 0 };
-
- if (pd_event_msg_match(pd_event, PD_EVT_DATA_MSG, PD_DATA_SOURCE_CAP)) {
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
- src_cap->nr = PD_HEADER_CNT(pd_msg->msg_hdr);
- memcpy(src_cap->pdos, pd_msg->payload,
- sizeof(u32) * src_cap->nr);
-
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SOURCE_CAP;
- } else {
- if (pd_event_msg_match(
- pd_event,
- PD_EVT_CTRL_MSG, PD_CTRL_REJECT))
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_SOURCE_CAP;
-
- src_cap->nr = 0;
- src_cap->pdos[0] = 0;
- }
-
- pd_dpm_update_pdos_flags(pd_port, src_cap->pdos[0]);
-}
-
-/*
- * DRP : Data Role Swap
- */
-
-void pd_dpm_drs_evaluate_swap(pd_port_t *pd_port, u8 role)
-{
- /* TODO : Check it later */
- pd_put_dpm_ack_event(pd_port);
-}
-
-void pd_dpm_drs_change_role(pd_port_t *pd_port, u8 role)
-{
- pd_set_data_role(pd_port, role);
-
- /* pd_put_dpm_ack_event(pd_port); */
- pd_port->dpm_ack_immediately = true;
-}
-
-/* Rules: */
- /* External Sources -> EXS */
- /* Provider/Consumers -> PC */
- /* Consumers/Provider -> CP */
-
- /* 1. PC (with EXS) shall always deny PR_SWAP from CP (without EXS) */
-
- /* 2. PC (without EXS) shall always acppet PR_SWAP from CP (with EXS) */
- /* unless the requester isn't able to provide PDOs. */
-
-void pd_dpm_prs_evaluate_swap(pd_port_t *pd_port, u8 role)
-{
- int good_power;
- bool accept = true;
- bool sink, check_src, check_snk, check_ext;
-
- check_src = (pd_port->dpm_caps & DPM_CAP_PR_SWAP_CHECK_GP_SRC) ? 1 : 0;
- check_snk = (pd_port->dpm_caps & DPM_CAP_PR_SWAP_CHECK_GP_SNK) ? 1 : 0;
- check_ext = (pd_port->dpm_flags & DPM_FLAGS_CHECK_EXT_POWER) ? 1 : 0;
-
- if (check_src | check_snk | check_ext) {
- sink = pd_port->power_role == PD_ROLE_SINK;
- good_power = dpm_check_good_power(pd_port);
-
- switch (good_power) {
- case GOOD_PW_PARTNER:
- if (sink && check_snk)
- accept = false;
- break;
-
- case GOOD_PW_LOCAL:
- if ((!sink) && (check_src || check_ext))
- accept = false;
- break;
-
- case GOOD_PW_NONE:
- accept = true;
- break;
-
- default:
- accept = true;
- break;
- }
- }
-
- dpm_response_request(pd_port, accept);
-}
-
-void pd_dpm_prs_turn_off_power_sink(pd_port_t *pd_port)
-{
- tcpci_sink_vbus(
- pd_port->tcpc_dev,
- TCP_VBUS_CTRL_PR_SWAP, TCPC_VBUS_SINK_0V, 0);
-}
-
-void pd_dpm_prs_enable_power_source(pd_port_t *pd_port, bool en)
-{
- int vbus_level = en ? TCPC_VBUS_SOURCE_5V : TCPC_VBUS_SOURCE_0V;
-
- tcpci_source_vbus(
- pd_port->tcpc_dev,
- TCP_VBUS_CTRL_PR_SWAP, vbus_level, -1);
-
- if (en)
- pd_enable_vbus_valid_detection(pd_port, en);
- else
- pd_enable_vbus_safe0v_detection(pd_port);
-}
-
-void pd_dpm_prs_change_role(pd_port_t *pd_port, u8 role)
-{
- pd_set_power_role(pd_port, role);
- pd_put_dpm_ack_event(pd_port);
-}
-
-/*
- * DRP : Vconn Swap
- */
-
-void pd_dpm_vcs_evaluate_swap(pd_port_t *pd_port)
-{
- bool accept = true;
-
- dpm_response_request(pd_port, accept);
-}
-
-void pd_dpm_vcs_enable_vconn(pd_port_t *pd_port, bool en)
-{
- pd_dpm_enable_vconn(pd_port, en);
-
- /* TODO: If we can't enable vconn immediately, */
- /* then after vconn_on, Vconn Controller */
- /*should pd_put_dpm_ack_event() */
-
- pd_port->dpm_ack_immediately = true;
-}
-
-/*
- * PE : Notify DPM
- */
-
-static inline int pd_dpm_ready_get_sink_cap(pd_port_t *pd_port)
-{
- if (!(pd_port->dpm_flags & DPM_FLAGS_CHECK_SINK_CAP))
- return 0;
-
- if (pd_port->get_snk_cap_count >= PD_GET_SNK_CAP_RETRIES)
- return 0;
-
- pd_port->get_snk_cap_count++;
- pd_put_dpm_pd_request_event(
- pd_port, PD_DPM_PD_REQUEST_GET_SINK_CAP);
-
- return 1;
-}
-
-static inline int pd_dpm_ready_get_source_cap(pd_port_t *pd_port)
-{
- if (!(pd_port->dpm_flags & DPM_FLAGS_CHECK_SOURCE_CAP))
- return 0;
-
- if (pd_port->get_src_cap_count >= PD_GET_SRC_CAP_RETRIES)
- return 0;
-
- pd_port->get_src_cap_count++;
- pd_put_dpm_pd_request_event(
- pd_port, PD_DPM_PD_REQUEST_GET_SOURCE_CAP);
-
- return 1;
-}
-
-static inline int pd_dpm_ready_attempt_get_extbit(pd_port_t *pd_port)
-{
- if (pd_port->remote_src_cap.nr >= 1)
- return 0;
-
- if (pd_port->remote_snk_cap.nr >= 1)
- return 0;
-
- if (!(pd_port->dpm_flags & DPM_FLAGS_CHECK_EXT_POWER))
- return 0;
-
- if (pd_port->get_snk_cap_count >= PD_GET_SNK_CAP_RETRIES)
- return 0;
-
- pd_port->get_snk_cap_count++;
- pd_put_dpm_pd_request_event(
- pd_port, PD_DPM_PD_REQUEST_GET_SINK_CAP);
- return 1;
-}
-
-static inline int pd_dpm_notify_pe_src_ready(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- return pd_dpm_ready_attempt_get_extbit(pd_port);
-}
-
-static inline int pd_dpm_notify_pe_dfp_ready(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- if (pd_port->dpm_flags & DPM_FLAGS_CHECK_CABLE_ID_DFP) {
- if (pd_is_auto_discover_cable_id(pd_port)) {
- if (!pd_port->vconn_source) {
- pd_port->vconn_return = true;
- pd_put_dpm_pd_request_event(
- pd_port,
- PD_DPM_PD_REQUEST_VCONN_SWAP);
- return 1;
- }
-
- pd_restart_timer(pd_port, PD_TIMER_DISCOVER_ID);
- return 1;
- }
- }
-
- if (pd_port->vconn_return) {
- DPM_DBG("VconnReturn\r\n");
- pd_port->vconn_return = false;
- if (pd_port->vconn_source) {
- pd_put_dpm_pd_request_event(
- pd_port,
- PD_DPM_PD_REQUEST_VCONN_SWAP);
- return 1;
- }
- }
-#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
-
-#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_ID
- if (pd_port->dpm_flags & DPM_FLAGS_CHECK_UFP_ID) {
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_UFP_ID;
- if (vdm_put_dpm_vdm_request_event(
- pd_port, PD_DPM_VDM_REQUEST_DISCOVER_ID))
- return 1;
- }
-#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_ID */
-
-#ifdef CONFIG_USB_PD_ATTEMP_DISCOVER_SVID
- if (pd_port->dpm_flags & DPM_FLAGS_CHECK_UFP_SVID) {
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_UFP_SVID;
- if (vdm_put_dpm_vdm_request_event(
- pd_port, PD_DPM_VDM_REQUEST_DISCOVER_SVIDS))
- return 1;
- }
-#endif /* CONFIG_USB_PD_ATTEMP_DISCOVER_SVID */
-
-#ifdef CONFIG_USB_PD_MODE_OPERATION
- if (svdm_notify_pe_ready(pd_port, pd_event))
- return 1;
-#endif /* CONFIG_USB_PD_MODE_OPERATION */
-
- return 0;
-}
-
-int pd_dpm_notify_pe_startup(pd_port_t *pd_port)
-{
- u32 caps, flags = 0;
-
- caps = DPM_CAP_EXTRACT_PR_CHECK(pd_port->dpm_caps);
- if (caps != DPM_CAP_PR_CHECK_DISABLE)
- flags |= DPM_FLAGS_CHECK_PR_ROLE;
-
- caps = DPM_CAP_EXTRACT_DR_CHECK(pd_port->dpm_caps);
- if (caps != DPM_CAP_DR_CHECK_DISABLE)
- flags |= DPM_FLAGS_CHECK_DR_ROLE;
-
- if (pd_port->dpm_caps & DPM_CAP_PR_SWAP_CHECK_GP_SRC)
- flags |= DPM_FLAGS_CHECK_EXT_POWER;
-
- if (pd_port->dpm_caps & DPM_CAP_PR_SWAP_CHECK_GP_SNK)
- flags |= DPM_FLAGS_CHECK_EXT_POWER;
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_EXT_POWER)
- flags |= DPM_FLAGS_CHECK_EXT_POWER;
-
- if (pd_port->dpm_caps & DPM_CAP_ATTEMP_DISCOVER_CABLE)
- flags |= DPM_FLAGS_CHECK_CABLE_ID;
-
- if (pd_port->dpm_caps & DPM_CAP_ATTEMP_DISCOVER_CABLE_DFP)
- flags |= DPM_FLAGS_CHECK_CABLE_ID_DFP;
-
- if (pd_port->dpm_caps & DPM_CAP_ATTEMP_DISCOVER_ID)
- flags |= DPM_FLAGS_CHECK_UFP_ID;
-
- pd_port->dpm_flags = flags;
- pd_port->dpm_dfp_retry_cnt = 2;
-
- svdm_notify_pe_startup(pd_port);
- return 0;
-}
-
-int pd_dpm_notify_pe_hardreset(pd_port_t *pd_port)
-{
- u32 flags = 0;
-
- if (pd_port->dpm_dfp_retry_cnt) {
- pd_port->dpm_dfp_retry_cnt--;
- pd_port->dpm_flags |= flags;
- svdm_notify_pe_startup(pd_port);
- }
-
- return 0;
-}
-
-int pd_dpm_notify_pe_ready(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- int ret = 0;
-
- if (pd_dpm_ready_get_source_cap(pd_port))
- return 1;
-
- if (pd_dpm_ready_get_sink_cap(pd_port))
- return 1;
-
- if (pd_port->power_role == PD_ROLE_SOURCE)
- ret = pd_dpm_notify_pe_src_ready(pd_port, pd_event);
-
- if (ret != 0)
- return ret;
-
- if (pd_port->data_role == PD_ROLE_DFP)
- ret = pd_dpm_notify_pe_dfp_ready(pd_port, pd_event);
-
- if (ret != 0)
- return ret;
-
- if (!pd_port->pe_ready) {
- pd_port->pe_ready = true;
- pd_update_connect_state(pd_port, PD_CONNECT_PE_READY);
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef PD_DPM_PRV_H_INCLUDED
-#define PD_DPM_PRV_H_INCLUDED
-
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-typedef struct __eval_snk_request_result {
- int src_sel;
- int snk_sel;
-} eval_snk_request_result_t;
-
-#define SVID_DATA_LOCAL_MODE(svid_data, n) \
- ((svid_data)->local_mode.mode_vdo[n])
-
-#define SVID_DATA_REMOTE_MODE(svid_data, n) \
- ((svid_data)->remote_mode.mode_vdo[n])
-
-#define SVID_DATA_DFP_GET_ACTIVE_MODE(svid_data)\
- SVID_DATA_REMOTE_MODE(svid_data, svid_data->active_mode - 1)
-
-#define SVID_DATA_UFP_GET_ACTIVE_MODE(svid_data)\
- SVID_DATA_LOCAL_MODE(svid_data, svid_data->active_mode - 1)
-
-bool eval_snk_cap_request(
- const pd_port_power_caps *snk_caps,
- const pd_port_power_caps *src_caps,
- int strategy,
- eval_snk_request_result_t *result);
-
-enum pd_ufp_u_state {
- DP_UFP_U_NONE = 0,
- DP_UFP_U_STARTUP,
- DP_UFP_U_WAIT,
- DP_UFP_U_OPERATION,
- DP_UFP_U_STATE_NR,
-
- DP_UFP_U_ERR = 0X10,
-
- DP_DFP_U_ERR_DP_CONNECTED,
-};
-
-typedef struct __pd_mode_prop {
- const char *name;
- u32 svid;
- void (*request_enter_mode)(pd_port_t *pd_port);
- void (*request_exit_mode)(pd_port_t *pd_port);
- bool (*dfp_inform_id)(
- pd_port_t *pd_port,
- pd_event_t *pd_event, bool ack);
- bool (*dfp_inform_svids)(pd_port_t *pd_port, bool ack);
- bool (*dfp_inform_modes)(pd_port_t *pd_port, bool ack);
- bool (*dfp_inform_enter_mode)(pd_port_t *pd_port, bool ack);
- bool (*dfp_inform_exit_mode)(pd_port_t *pd_port, u16 svid);
- bool (*dfp_inform_attention)(pd_port_t *pd_port, pd_event_t *pd_event);
- bool (*notify_pe_dfp_ready)(pd_port_t *pd_port, pd_event_t *pd_event);
- void (*reset_state)(pd_port_t *pd_port);
-} pd_mode_prop_t;
-
-typedef struct __svdm_svid_ops {
- const char *name;
- u16 svid;
-
- bool (*dfp_inform_id)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data,
- pd_event_t *pd_event, bool ack);
- bool (*dfp_inform_svids)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, bool ack);
- bool (*dfp_inform_modes)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, bool ack);
-
- bool (*dfp_inform_enter_mode)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, u8 ops, bool ack);
- bool (*dfp_inform_exit_mode)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, u8 ops);
-
- bool (*dfp_inform_attention)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, pd_event_t *pd_event);
-
- void (*ufp_request_enter_mode)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, u8 ops);
- void (*ufp_request_exit_mode)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, u8 ops);
-
- bool (*notify_pe_startup)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data);
- int (*notify_pe_ready)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data, pd_event_t *pd_event);
-
- bool (*reset_state)(
- pd_port_t *pd_port,
- svdm_svid_data_t *svid_data);
-} svdm_svid_ops_t;
-
-static inline svdm_svid_data_t *
- dpm_get_svdm_svid_data(pd_port_t *pd_port, u16 svid)
-{
- u8 i;
- svdm_svid_data_t *svid_data;
-
- if (!(pd_port->id_vdos[0] & PD_IDH_MODAL_SUPPORT))
- return NULL;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->svid == svid)
- return svid_data;
- }
-
- return NULL;
-}
-
-static inline void dpm_vdm_get_svid_ops(
- pd_event_t *pd_event, u16 *svid, u8 *ops)
-{
- u32 vdm_hdr;
- char buf[1024] = { 0 };
-
- if (!pd_event->pd_msg)
- snprintf(buf, sizeof(buf), "the pd msg is NULL\n");
- vdm_hdr = pd_event->pd_msg->payload[0];
- if (svid)
- *svid = PD_VDO_VID(vdm_hdr);
- if (ops)
- *ops = PD_VDO_OPOS(vdm_hdr);
-}
-
-static inline bool dpm_register_svdm_ops(
- pd_port_t *pd_port, const svdm_svid_ops_t *ops)
-{
- svdm_svid_data_t *svid_data =
- dpm_get_svdm_svid_data(pd_port, ops->svid);
- if (!svid_data)
- return false;
-
- svid_data->ops = ops;
- return true;
-}
-
-static inline bool svdm_notify_pe_startup(pd_port_t *pd_port)
-{
- int i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->ops && svid_data->ops->notify_pe_startup)
- svid_data->ops->notify_pe_startup(pd_port, svid_data);
- }
-
- return true;
-}
-
-static inline int svdm_notify_pe_ready(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- int i, ret;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->ops && svid_data->ops->notify_pe_ready) {
- ret = svid_data->ops->notify_pe_ready(
- pd_port, svid_data, pd_event);
-
- if (ret != 0)
- return ret;
- }
- }
-
- return 0;
-}
-
-static inline bool svdm_reset_state(pd_port_t *pd_port)
-{
- int i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->ops && svid_data->ops->reset_state)
- svid_data->ops->reset_state(pd_port, svid_data);
- }
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_id(
- pd_port_t *pd_port, pd_event_t *pd_event, bool ack)
-{
- int i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->ops && svid_data->ops->dfp_inform_id)
- svid_data->ops->dfp_inform_id(
- pd_port, svid_data, pd_event, ack);
- }
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_svids(pd_port_t *pd_port, bool ack)
-{
- int i;
- svdm_svid_data_t *svid_data;
-
- for (i = 0; i < pd_port->svid_data_cnt; i++) {
- svid_data = &pd_port->svid_data[i];
- if (svid_data->ops && svid_data->ops->dfp_inform_svids)
- svid_data->ops->dfp_inform_svids(
- pd_port, svid_data, ack);
- }
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_modes(
- pd_port_t *pd_port, u16 svid, bool ack)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->dfp_inform_modes)
- svid_data->ops->dfp_inform_modes(pd_port, svid_data, ack);
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_enter_mode(
- pd_port_t *pd_port, u16 svid, u8 ops, bool ack)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->dfp_inform_enter_mode)
- svid_data->ops->dfp_inform_enter_mode(
- pd_port, svid_data, ops, ack);
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_exit_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->dfp_inform_exit_mode)
- svid_data->ops->dfp_inform_exit_mode(pd_port, svid_data, ops);
-
- return true;
-}
-
-static inline bool svdm_dfp_inform_attention(
- pd_port_t *pd_port, u16 svid, pd_event_t *pd_event)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->dfp_inform_attention)
- svid_data->ops->dfp_inform_attention(
- pd_port, svid_data, pd_event);
-
- return true;
-}
-
-static inline bool svdm_ufp_request_enter_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->ufp_request_enter_mode)
- svid_data->ops->ufp_request_enter_mode(pd_port, svid_data, ops);
-
- return true;
-}
-
-static inline bool svdm_ufp_request_exit_mode(
- pd_port_t *pd_port, u16 svid, u8 ops)
-{
- svdm_svid_data_t *svid_data;
-
- svid_data = dpm_get_svdm_svid_data(pd_port, svid);
- if (!svid_data)
- return false;
-
- if (svid_data->ops && svid_data->ops->ufp_request_exit_mode)
- svid_data->ops->ufp_request_exit_mode(pd_port, svid_data, ops);
-
- return true;
-}
-
-#endif /* PD_DPM_PRV_H_INCLUDED */
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-/* ---- Policy Engine State ---- */
-
-#if PE_STATE_FULL_NAME
-
-static const char *const pe_state_name[] = {
- "PE_SRC_STARTUP",
- "PE_SRC_DISCOVERY",
- "PE_SRC_SEND_CAPABILITIES",
- "PE_SRC_NEGOTIATE_CAPABILITIES",
- "PE_SRC_TRANSITION_SUPPLY",
- "PE_SRC_TRANSITION_SUPPLY2",
- "PE_SRC_READY",
- "PE_SRC_DISABLED",
- "PE_SRC_CAPABILITY_RESPONSE",
- "PE_SRC_HARD_RESET",
- "PE_SRC_HARD_RESET_RECEIVED",
- "PE_SRC_TRANSITION_TO_DEFAULT",
- "PE_SRC_GIVE_SOURCE_CAP",
- "PE_SRC_GET_SINK_CAP",
- "PE_SRC_WAIT_NEW_CAPABILITIES",
-
- "PE_SRC_SEND_SOFT_RESET",
- "PE_SRC_SOFT_RESET",
- "PE_SRC_PING",
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- "PE_SRC_VDM_IDENTITY_REQUEST",
- "PE_SRC_VDM_IDENTITY_ACKED",
- "PE_SRC_VDM_IDENTITY_NAKED",
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
-
- "PE_SNK_STARTUP",
- "PE_SNK_DISCOVERY",
- "PE_SNK_WAIT_FOR_CAPABILITIES",
- "PE_SNK_EVALUATE_CAPABILITY",
- "PE_SNK_SELECT_CAPABILITY",
- "PE_SNK_TRANSITION_SINK",
- "PE_SNK_READY",
- "PE_SNK_HARD_RESET",
- "PE_SNK_TRANSITION_TO_DEFAULT",
- "PE_SNK_GIVE_SINK_CAP",
- "PE_SNK_GET_SOURCE_CAP",
-
- "PE_SNK_SEND_SOFT_RESET",
- "PE_SNK_SOFT_RESET",
-
- "PE_DRS_DFP_UFP_EVALUATE_DR_SWAP",
- "PE_DRS_DFP_UFP_ACCEPT_DR_SWAP",
- "PE_DRS_DFP_UFP_CHANGE_TO_UFP",
- "PE_DRS_DFP_UFP_SEND_DR_SWAP",
- "PE_DRS_DFP_UFP_REJECT_DR_SWAP",
-
- "PE_DRS_UFP_DFP_EVALUATE_DR_SWAP",
- "PE_DRS_UFP_DFP_ACCEPT_DR_SWAP",
- "PE_DRS_UFP_DFP_CHANGE_TO_DFP",
- "PE_DRS_UFP_DFP_SEND_SWAP",
- "PE_DRS_UFP_DFP_REJECT_DR_SWAP",
-
- "PE_PRS_SRC_SNK_EVALUATE_PR_SWAP",
- "PE_PRS_SRC_SNK_ACCEPT_PR_SWAP",
- "PE_PRS_SRC_SNK_TRANSITION_TO_OFF",
- "PE_PRS_SRC_SNK_ASSERT_RD",
- "PE_PRS_SRC_SNK_WAIT_SOURCE_ON",
- "PE_PRS_SRC_SNK_SEND_SWAP",
- "PE_PRS_SRC_SNK_REJECT_PR_SWAP",
-
- "PE_PRS_SNK_SRC_EVALUATE_PR_SWAP",
- "PE_PRS_SNK_SRC_ACCEPT_PR_SWAP",
- "PE_PRS_SNK_SRC_TRANSITION_TO_OFF",
- "PE_PRS_SNK_SRC_ASSERT_RP",
- "PE_PRS_SNK_SRC_SOURCE_ON",
- "PE_PRS_SNK_SRC_SEND_PR_SWAP",
- "PE_PRS_SNK_SRC_REJECT_SWAP",
-
- "PE_DR_SRC_GET_SOURCE_CAP",
-
- "PE_DR_SRC_GIVE_SINK_CAP",
-
- "PE_DR_SNK_GET_SINK_CAP",
-
- "PE_DR_SNK_GIVE_SOURCE_CAP",
-
- "PE_VCS_SEND_SWAP",
- "PE_VCS_EVALUATE_SWAP",
- "PE_VCS_ACCEPT_SWAP",
- "PE_VCS_REJECT_SWAP",
- "PE_VCS_WAIT_FOR_VCONN",
- "PE_VCS_TURN_OFF_VCONN",
- "PE_VCS_TURN_ON_VCONN",
- "PE_VCS_SEND_PS_RDY",
-
- "PE_UFP_VDM_GET_IDENTITY",
- "PE_UFP_VDM_SEND_IDENTITY",
- "PE_UFP_VDM_GET_IDENTITY_NAK",
-
- "PE_UFP_VDM_GET_SVIDS",
- "PE_UFP_VDM_SEND_SVIDS",
- "PE_UFP_VDM_GET_SVIDS_NAK",
-
- "PE_UFP_VDM_GET_MODES",
- "PE_UFP_VDM_SEND_MODES",
- "PE_UFP_VDM_GET_MODES_NAK",
-
- "PE_UFP_VDM_EVALUATE_MODE_ENTRY",
- "PE_UFP_VDM_MODE_ENTRY_ACK",
- "PE_UFP_VDM_MODE_ENTRY_NAK",
-
- "PE_UFP_VDM_MODE_EXIT",
- "PE_UFP_VDM_MODE_EXIT_ACK",
- "PE_UFP_VDM_MODE_EXIT_NAK",
-
- "PE_UFP_VDM_ATTENTION_REQUEST",
-
- "PE_DFP_UFP_VDM_IDENTITY_REQUEST",
- "PE_DFP_UFP_VDM_IDENTITY_ACKED",
- "PE_DFP_UFP_VDM_IDENTITY_NAKED",
-
- "PE_DFP_CBL_VDM_IDENTITY_REQUEST",
- "PE_DFP_CBL_VDM_IDENTITY_ACKED",
- "PE_DFP_CBL_VDM_IDENTITY_NAKED",
-
- "PE_DFP_VDM_SVIDS_REQUEST",
- "PE_DFP_VDM_SVIDS_ACKED",
- "PE_DFP_VDM_SVIDS_NAKED",
-
- "PE_DFP_VDM_MODES_REQUEST",
- "PE_DFP_VDM_MODES_ACKED",
- "PE_DFP_VDM_MODES_NAKED",
-
- "PE_DFP_VDM_MODE_ENTRY_REQUEST",
- "PE_DFP_VDM_MODE_ENTRY_ACKED",
- "PE_DFP_VDM_MODE_ENTRY_NAKED",
-
- "PE_DFP_VDM_MODE_EXIT_REQUEST",
- "PE_DFP_VDM_MODE_EXIT_ACKED",
-
- "PE_DFP_VDM_ATTENTION_REQUEST",
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- "PE_DBG_READY",
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
-
- "PE_BIST_TEST_DATA",
- "PE_BIST_CARRIER_MODE_2",
-
- "PE_IDLE1",
- "PE_IDLE2",
-
- "PE_VIRT_HARD_RESET",
- "PE_VIRT_READY",
-};
-#else
-
-static const char *const pe_state_name[] = {
- "SRC_START",
- "SRC_DISCOVERY",
- "SRC_SEND_CAP",
- "SRC_NEG_CAP",
- "SRC_TRANS_SUPPLY",
- "SRC_TRANS_SUPPLY2",
- "SRC_READY",
- "SRC_DISABLED",
- "SRC_CAP_RESP",
- "SRC_HRESET",
- "SRC_HRESET_RECV",
- "SRC_TRANS_DFT",
- "SRC_GIVE_CAP",
- "SRC_GET_CAP",
- "SRC_WAIT_CAP",
-
- "SRC_SEND_SRESET",
- "SRC_SRESET",
- "SRC_PING",
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- "SRC_VDM_ID_REQ",
- "SRC_VDM_ID_ACK",
- "SRC_VDM_ID_NAK",
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
-
- "SNK_START",
- "SNK_DISCOVERY",
- "SNK_WAIT_CAP",
- "SNK_EVA_CAP",
- "SNK_SEL_CAP",
- "SNK_TRANS_SINK",
- "SNK_READY",
- "SNK_HRESET",
- "SNK_TRANS_DFT",
- "SNK_GIVE_CAP",
- "SNK_GET_CAP",
-
- "SNK_SEND_SRESET",
- "SNK_SRESET",
-
- "D_DFP_EVALUATE",
- "D_DFP_ACCEPT",
- "D_DFP_CHANGE",
- "D_DFP_SEND",
- "D_DFP_REJECT",
-
- "D_UFP_EVALUATE",
- "D_UFP_ACCEPT",
- "D_UFP_CHANGE",
- "D_UFP_SEND",
- "D_UFP_REJECT",
-
- "P_SRC_EVALUATE",
- "P_SRC_ACCEPT",
- "P_SRC_TRANS_OFF",
- "P_SRC_ASSERT",
- "P_SRC_WAIT_ON",
- "P_SRC_SEND",
- "P_SRC_REJECT",
-
- "P_SNK_EVALUATE",
- "P_SNK_ACCEPT",
- "P_SNK_TRANS_OFF",
- "P_SNK_ASSERT",
- "P_SNK_SOURCE_ON",
- "P_SNK_SEND",
- "P_SNK_REJECT",
-
- "DR_SRC_GET_CAP", /* get source cap */
- "DR_SRC_GIVE_CAP", /* give sink cap */
- "DR_SNK_GET_CAP", /* get sink cap */
- "DR_SNK_GIVE_CAP", /* give source cap */
-
- "V_SEND",
- "V_EVALUATE",
- "V_ACCEPT",
- "V_REJECT",
- "V_WAIT_VCONN",
- "V_TURN_OFF",
- "V_TURN_ON",
- "V_PS_RDY",
-
- "U_GET_ID",
- "U_SEND_ID",
- "U_GET_ID_N",
-
- "U_GET_SVID",
- "U_SEND_SVID",
- "U_GET_SVID_N",
-
- "U_GET_MODE",
- "U_SEND_MODE",
- "U_GET_MODE_N",
-
- "U_EVA_MODE",
- "U_MODE_EN_A",
- "U_MODE_EN_N",
-
- "U_MODE_EX",
- "U_MODE_EX_A",
- "U_MODE_EX_N",
-
- "U_ATTENTION",
-
- "D_UID_REQ",
- "D_UID_A",
- "D_UID_N",
-
- "D_CID_REQ",
- "D_CID_ACK",
- "D_CID_NAK",
-
- "D_SVID_REQ",
- "D_SVID_ACK",
- "D_SVID_NAK",
-
- "D_MODE_REQ",
- "D_MODE_ACK",
- "D_MODE_NAK",
-
- "D_MODE_EN_REQ",
- "D_MODE_EN_ACK",
- "D_MODE_EN_NAK",
-
- "D_MODE_EX_REQ",
- "D_MODE_EX_ACK",
-
- "D_ATTENTION",
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- "DBG_READY",
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
-
- "ERR_RECOVERY",
-
- "BIST_TD",
- "BIST_C2",
-
- "IDLE1",
- "IDLE2",
-
- "VIRT_HARD_RESET",
- "VIRT_READY",
-};
-
-#endif
-
-typedef void (*pe_state_action_fcn_t)
- (pd_port_t *pd_port, pd_event_t *pd_event);
-
-typedef struct __pe_state_actions {
- const pe_state_action_fcn_t entry_action;
- /* const pd_pe_state_action_fcn_t exit_action; */
-} pe_state_actions_t;
-
-#define PE_STATE_ACTIONS(state) { .entry_action = state##_entry, }
-
-/*
- * Policy Engine General State Activity
- */
-
-/* extern int rt1711_set_bist_carrier_mode( */
-/* struct tcpc_device *tcpc_dev, uint8_t pattern); */
-static void pe_idle_reset_data(pd_port_t *pd_port)
-{
- pd_reset_pe_timer(pd_port);
- pd_reset_svid_data(pd_port);
-
- pd_port->pd_prev_connected = false;
- pd_port->state_machine = PE_STATE_MACHINE_IDLE;
-
- switch (pd_port->pe_state_curr) {
- case PE_BIST_TEST_DATA:
- pd_enable_bist_test_mode(pd_port, false);
- break;
-
- case PE_BIST_CARRIER_MODE_2:
- pd_disable_bist_mode2(pd_port);
- break;
- }
-
- pd_unlock_msg_output(pd_port);
-}
-
-static void pe_idle1_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pe_idle_reset_data(pd_port);
-
- pd_try_put_pe_idle_event(pd_port);
-}
-
-static void pe_idle2_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE);
- pd_notify_pe_idle(pd_port);
-}
-
-void pe_error_recovery_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pe_idle_reset_data(pd_port);
-
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_IDLE);
- pd_notify_pe_error_recovery(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_bist_test_data_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_bist_test_mode(pd_port, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_bist_test_data_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_bist_test_mode(pd_port, false);
-}
-
-void pe_bist_carrier_mode_2_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_bist_mode2(pd_port);
- pd_enable_timer(pd_port, PD_TIMER_BIST_CONT_MODE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_bist_carrier_mode_2_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_BIST_CONT_MODE);
- pd_disable_bist_mode2(pd_port);
-}
-
-/*
- * Policy Engine Share State Activity
- */
-
-void pe_power_ready_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->during_swap = false;
- pd_port->explicit_contract = true;
-
- if (pd_port->data_role == PD_ROLE_UFP)
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_UFP);
- else
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_DFP);
-
- pd_dpm_notify_pe_ready(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-static const pe_state_actions_t pe_state_actions[] = {
- /* src activity */
- PE_STATE_ACTIONS(pe_src_startup),
- PE_STATE_ACTIONS(pe_src_discovery),
- PE_STATE_ACTIONS(pe_src_send_capabilities),
- PE_STATE_ACTIONS(pe_src_negotiate_capabilities),
- PE_STATE_ACTIONS(pe_src_transition_supply),
- PE_STATE_ACTIONS(pe_src_transition_supply2),
- PE_STATE_ACTIONS(pe_src_ready),
- PE_STATE_ACTIONS(pe_src_disabled),
- PE_STATE_ACTIONS(pe_src_capability_response),
- PE_STATE_ACTIONS(pe_src_hard_reset),
- PE_STATE_ACTIONS(pe_src_hard_reset_received),
- PE_STATE_ACTIONS(pe_src_transition_to_default),
- PE_STATE_ACTIONS(pe_src_give_source_cap),
- PE_STATE_ACTIONS(pe_src_get_sink_cap),
- PE_STATE_ACTIONS(pe_src_wait_new_capabilities),
-
- PE_STATE_ACTIONS(pe_src_send_soft_reset),
- PE_STATE_ACTIONS(pe_src_soft_reset),
- PE_STATE_ACTIONS(pe_src_ping),
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- PE_STATE_ACTIONS(pe_src_vdm_identity_request),
- PE_STATE_ACTIONS(pe_src_vdm_identity_acked),
- PE_STATE_ACTIONS(pe_src_vdm_identity_naked),
-#endif
-
- /* snk activity */
- PE_STATE_ACTIONS(pe_snk_startup),
- PE_STATE_ACTIONS(pe_snk_discovery),
- PE_STATE_ACTIONS(pe_snk_wait_for_capabilities),
- PE_STATE_ACTIONS(pe_snk_evaluate_capability),
- PE_STATE_ACTIONS(pe_snk_select_capability),
- PE_STATE_ACTIONS(pe_snk_transition_sink),
- PE_STATE_ACTIONS(pe_snk_ready),
- PE_STATE_ACTIONS(pe_snk_hard_reset),
- PE_STATE_ACTIONS(pe_snk_transition_to_default),
- PE_STATE_ACTIONS(pe_snk_give_sink_cap),
- PE_STATE_ACTIONS(pe_snk_get_source_cap),
-
- PE_STATE_ACTIONS(pe_snk_send_soft_reset),
- PE_STATE_ACTIONS(pe_snk_soft_reset),
-
- /* drs dfp activity */
- PE_STATE_ACTIONS(pe_drs_dfp_ufp_evaluate_dr_swap),
- PE_STATE_ACTIONS(pe_drs_dfp_ufp_accept_dr_swap),
- PE_STATE_ACTIONS(pe_drs_dfp_ufp_change_to_ufp),
- PE_STATE_ACTIONS(pe_drs_dfp_ufp_send_dr_swap),
- PE_STATE_ACTIONS(pe_drs_dfp_ufp_reject_dr_swap),
-
- /* drs ufp activity */
- PE_STATE_ACTIONS(pe_drs_ufp_dfp_evaluate_dr_swap),
- PE_STATE_ACTIONS(pe_drs_ufp_dfp_accept_dr_swap),
- PE_STATE_ACTIONS(pe_drs_ufp_dfp_change_to_dfp),
- PE_STATE_ACTIONS(pe_drs_ufp_dfp_send_dr_swap),
- PE_STATE_ACTIONS(pe_drs_ufp_dfp_reject_dr_swap),
-
- /* prs src activity */
- PE_STATE_ACTIONS(pe_prs_src_snk_evaluate_pr_swap),
- PE_STATE_ACTIONS(pe_prs_src_snk_accept_pr_swap),
- PE_STATE_ACTIONS(pe_prs_src_snk_transition_to_off),
- PE_STATE_ACTIONS(pe_prs_src_snk_assert_rd),
- PE_STATE_ACTIONS(pe_prs_src_snk_wait_source_on),
- PE_STATE_ACTIONS(pe_prs_src_snk_send_swap),
- PE_STATE_ACTIONS(pe_prs_src_snk_reject_pr_swap),
-
- /* prs snk activity */
- PE_STATE_ACTIONS(pe_prs_snk_src_evaluate_pr_swap),
- PE_STATE_ACTIONS(pe_prs_snk_src_accept_pr_swap),
- PE_STATE_ACTIONS(pe_prs_snk_src_transition_to_off),
- PE_STATE_ACTIONS(pe_prs_snk_src_assert_rp),
- PE_STATE_ACTIONS(pe_prs_snk_src_source_on),
- PE_STATE_ACTIONS(pe_prs_snk_src_send_swap),
- PE_STATE_ACTIONS(pe_prs_snk_src_reject_swap),
-
- /* dr src activity */
- PE_STATE_ACTIONS(pe_dr_src_get_source_cap),
- PE_STATE_ACTIONS(pe_dr_src_give_sink_cap),
-
- /* dr snk activity */
- PE_STATE_ACTIONS(pe_dr_snk_get_sink_cap),
- PE_STATE_ACTIONS(pe_dr_snk_give_source_cap),
-
- /* vcs activity */
- PE_STATE_ACTIONS(pe_vcs_send_swap),
- PE_STATE_ACTIONS(pe_vcs_evaluate_swap),
- PE_STATE_ACTIONS(pe_vcs_accept_swap),
- PE_STATE_ACTIONS(pe_vcs_reject_vconn_swap),
- PE_STATE_ACTIONS(pe_vcs_wait_for_vconn),
- PE_STATE_ACTIONS(pe_vcs_turn_off_vconn),
- PE_STATE_ACTIONS(pe_vcs_turn_on_vconn),
- PE_STATE_ACTIONS(pe_vcs_send_ps_rdy),
-
- /* ufp structured vdm activity */
- PE_STATE_ACTIONS(pe_ufp_vdm_get_identity),
- PE_STATE_ACTIONS(pe_ufp_vdm_send_identity),
- PE_STATE_ACTIONS(pe_ufp_vdm_get_identity_nak),
-
- PE_STATE_ACTIONS(pe_ufp_vdm_get_svids),
- PE_STATE_ACTIONS(pe_ufp_vdm_send_svids),
- PE_STATE_ACTIONS(pe_ufp_vdm_get_svids_nak),
-
- PE_STATE_ACTIONS(pe_ufp_vdm_get_modes),
- PE_STATE_ACTIONS(pe_ufp_vdm_send_modes),
- PE_STATE_ACTIONS(pe_ufp_vdm_get_modes_nak),
-
- PE_STATE_ACTIONS(pe_ufp_vdm_evaluate_mode_entry),
- PE_STATE_ACTIONS(pe_ufp_vdm_mode_entry_ack),
- PE_STATE_ACTIONS(pe_ufp_vdm_mode_entry_nak),
-
- PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit),
- PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit_ack),
- PE_STATE_ACTIONS(pe_ufp_vdm_mode_exit_nak),
-
- PE_STATE_ACTIONS(pe_ufp_vdm_attention_request),
-
- /* dfp structured vdm */
- PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_request),
- PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_acked),
- PE_STATE_ACTIONS(pe_dfp_ufp_vdm_identity_naked),
-
- PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_request),
- PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_acked),
- PE_STATE_ACTIONS(pe_dfp_cbl_vdm_identity_naked),
-
- PE_STATE_ACTIONS(pe_dfp_vdm_svids_request),
- PE_STATE_ACTIONS(pe_dfp_vdm_svids_acked),
- PE_STATE_ACTIONS(pe_dfp_vdm_svids_naked),
-
- PE_STATE_ACTIONS(pe_dfp_vdm_modes_request),
- PE_STATE_ACTIONS(pe_dfp_vdm_modes_acked),
- PE_STATE_ACTIONS(pe_dfp_vdm_modes_naked),
-
- PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_request),
- PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_acked),
- PE_STATE_ACTIONS(pe_dfp_vdm_mode_entry_naked),
-
- PE_STATE_ACTIONS(pe_dfp_vdm_mode_exit_request),
- PE_STATE_ACTIONS(pe_dfp_vdm_mode_exit_acked),
-
- PE_STATE_ACTIONS(pe_dfp_vdm_attention_request),
-
- /* general activity */
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- PE_STATE_ACTIONS(pe_dbg_ready),
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
- PE_STATE_ACTIONS(pe_error_recovery),
-
- PE_STATE_ACTIONS(pe_bist_test_data),
- PE_STATE_ACTIONS(pe_bist_carrier_mode_2),
-
- PE_STATE_ACTIONS(pe_idle1),
- PE_STATE_ACTIONS(pe_idle2),
-};
-
-static void pe_exit_action_disable_sender_response(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
-}
-
-pe_state_action_fcn_t pe_get_exit_action(uint8_t pe_state)
-{
- pe_state_action_fcn_t retval = NULL;
-
- switch (pe_state) {
- /* Source */
- case PE_SRC_SEND_CAPABILITIES:
- retval = pe_src_send_capabilities_exit;
- break;
- case PE_SRC_TRANSITION_SUPPLY:
- retval = pe_src_transition_supply_exit;
- break;
- case PE_SRC_TRANSITION_TO_DEFAULT:
- retval = pe_src_transition_to_default_exit;
- break;
- case PE_SRC_GET_SINK_CAP:
- retval = pe_src_get_sink_cap_exit;
- break;
-
- /* Sink */
- case PE_SNK_WAIT_FOR_CAPABILITIES:
- retval = pe_snk_wait_for_capabilities_exit;
- break;
- case PE_SNK_SELECT_CAPABILITY:
- retval = pe_snk_select_capability_exit;
- break;
- case PE_SNK_TRANSITION_SINK:
- retval = pe_snk_transition_sink_exit;
- break;
- case PE_SNK_TRANSITION_TO_DEFAULT:
- retval = pe_snk_transition_to_default_exit;
- break;
-
- case PE_DR_SRC_GET_SOURCE_CAP:
- retval = pe_dr_src_get_source_cap_exit;
- break;
- case PE_DR_SNK_GET_SINK_CAP:
- retval = pe_dr_snk_get_sink_cap_exit;
- break;
-
- case PE_BIST_TEST_DATA:
- retval = pe_bist_test_data_exit;
- break;
-
- case PE_BIST_CARRIER_MODE_2:
- retval = pe_bist_carrier_mode_2_exit;
- break;
-
- case PE_VCS_SEND_SWAP:
- case PE_PRS_SRC_SNK_SEND_SWAP:
- case PE_PRS_SNK_SRC_SEND_SWAP:
- case PE_DRS_DFP_UFP_SEND_DR_SWAP:
- case PE_DRS_UFP_DFP_SEND_DR_SWAP:
- retval = pe_exit_action_disable_sender_response;
- break;
-
- case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
- retval = pe_prs_src_snk_wait_source_on_exit;
- break;
-
- case PE_PRS_SNK_SRC_SOURCE_ON:
- retval = pe_prs_snk_src_source_on_exit;
- break;
-
- case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
- retval = pe_prs_snk_src_transition_to_off_exit;
- break;
-
- case PE_VCS_WAIT_FOR_VCONN:
- retval = pe_vcs_wait_for_vconn_exit;
- break;
- }
-
- return retval;
-}
-
-static void pd_pe_state_change(
- pd_port_t *pd_port, pd_event_t *pd_event, bool vdm_evt)
-{
- pe_state_action_fcn_t prev_exit_action;
- pe_state_action_fcn_t next_entry_action;
-
- u8 old_state = pd_port->pe_state_curr;
- u8 new_state = pd_port->pe_state_next;
- char buf[1024] = { 0 };
-
- if ((old_state >= PD_NR_PE_STATES) || (new_state >= PD_NR_PE_STATES))
- snprintf(buf, sizeof(buf), "the pd nr pe states\n");
- if ((new_state == PE_IDLE1) || (new_state == PE_IDLE2))
- prev_exit_action = NULL;
- else
- prev_exit_action = pe_get_exit_action(old_state);
-
- next_entry_action = pe_state_actions[new_state].entry_action;
-
- /*
- * Source (P, Provider), Sink (C, Consumer)
- * DFP (D), UFP (U)
- * Vconn Source (Y/N)
- */
-
-#if PE_DBG_ENABLE
- PE_DBG("%s -> %s (%c%c%c)\r\n",
- vdm_evt ? "VDM" : "PD", pe_state_name[new_state],
- pd_port->power_role ? 'P' : 'C',
- pd_port->data_role ? 'D' : 'U',
- pd_port->vconn_source ? 'Y' : 'N');
-#else
- if (!vdm_evt) {
- PE_STATE_INFO("%s-> %s\r\n",
- vdm_evt ? "VDM" : "PD", pe_state_name[new_state]);
- }
-#endif
-
- if (prev_exit_action)
- prev_exit_action(pd_port, pd_event);
-
- if (next_entry_action)
- next_entry_action(pd_port, pd_event);
-
- if (vdm_evt)
- pd_port->pe_vdm_state = new_state;
- else
- pd_port->pe_pd_state = new_state;
-}
-
-static int pd_handle_event(
- pd_port_t *pd_port, pd_event_t *pd_event, bool vdm_evt)
-{
- if (vdm_evt) {
- if (pd_port->reset_vdm_state) {
- pd_port->reset_vdm_state = false;
- pd_port->pe_vdm_state = pd_port->pe_pd_state;
- }
-
- pd_port->pe_state_curr = pd_port->pe_vdm_state;
- } else {
- pd_port->pe_state_curr = pd_port->pe_pd_state;
- }
-
- if (pd_process_event(pd_port, pd_event, vdm_evt))
- pd_pe_state_change(pd_port, pd_event, vdm_evt);
- else
- pd_free_pd_event(pd_port, pd_event);
-
- return 1;
-}
-
-static inline int pd_put_dpm_ack_immediately(
- pd_port_t *pd_port, bool vdm_evt)
-{
- pd_event_t pd_event = {
- .event_type = PD_EVT_DPM_MSG,
- .msg = PD_DPM_ACK,
- .pd_msg = NULL,
- };
-
- pd_handle_event(pd_port, &pd_event, vdm_evt);
-
- PE_DBG("ACK_Immediately\r\n");
- pd_port->dpm_ack_immediately = false;
- return 1;
-}
-
-int pd_policy_engine_run(struct tcpc_device *tcpc_dev)
-{
- bool vdm_evt = false;
- pd_event_t pd_event;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- if (!pd_get_event(tcpc_dev, &pd_event)) {
- switch (pd_port->pe_pd_state) {
- case PE_SNK_READY:
- case PE_SRC_READY:
- case PE_SRC_STARTUP:
- case PE_SRC_DISCOVERY:
- vdm_evt = pd_get_vdm_event(tcpc_dev, &pd_event);
- break;
- }
-
- if (!vdm_evt)
- return 0;
- }
- mutex_lock(&pd_port->pd_lock);
-
- pd_handle_event(pd_port, &pd_event, vdm_evt);
-
- if (pd_port->dpm_ack_immediately)
- pd_put_dpm_ack_immediately(pd_port, vdm_evt);
-
- mutex_unlock(&pd_port->pd_lock);
-
- return 1;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for DBGACC
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
-
-void pe_dbg_ready_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u8 state;
-
- if (pd_port->pe_ready)
- return;
-
- pd_port->pe_ready = true;
- pd_port->state_machine = PE_STATE_MACHINE_DBGACC;
-
- if (pd_port->data_role == PD_ROLE_UFP) {
- PE_INFO("Custom_DBGACC : UFP\r\n");
- state = PD_CONNECT_PE_READY_DBGACC_UFP;
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_UFP);
- } else {
- PE_INFO("Custom_DBGACC : DFP\r\n");
- state = PD_CONNECT_PE_READY_DBGACC_DFP;
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_READY_DFP);
- }
-
- pd_reset_protocol_layer(pd_port);
- pd_update_connect_state(pd_port, state);
-}
-
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for DFP
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-64 DFP to UFP VDM Discover Identity State Diagram
- */
-
-void pe_dfp_ufp_vdm_identity_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP);
-}
-
-void pe_dfp_ufp_vdm_identity_acked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_id(pd_port, pd_event, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_ufp_vdm_identity_naked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_id(pd_port, pd_event, false);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-65 DFP VDM Discover Identity State Diagram
- */
-
-void pe_dfp_cbl_vdm_identity_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP_PRIME);
- pd_port->discover_id_counter++;
-
- pd_enable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_cbl_vdm_identity_acked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->dpm_flags &=
- ~(DPM_FLAGS_CHECK_CABLE_ID | DPM_FLAGS_CHECK_CABLE_ID_DFP);
-
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_cable_vdo(pd_port, pd_event);
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_cbl_vdm_identity_naked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_cable_vdo(pd_port, pd_event);
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-66 DFP VDM Discover SVIDs State Diagram
- */
-
-void pe_dfp_vdm_svids_request_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_discover_svids(pd_port, TCPC_TX_SOP);
-}
-
-void pe_dfp_vdm_svids_acked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_svids(pd_port, pd_event, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_vdm_svids_naked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_svids(pd_port, pd_event, false);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-67 DFP VDM Discover Modes State Diagram
- */
-
-void pe_dfp_vdm_modes_request_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_discover_modes(pd_port, TCPC_TX_SOP, pd_port->mode_svid);
-}
-
-void pe_dfp_vdm_modes_acked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_modes(pd_port, pd_event, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_vdm_modes_naked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_modes(pd_port, pd_event, false);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-68 DFP VDM Mode Entry State Diagram
- */
-
-void pe_dfp_vdm_mode_entry_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_enter_mode(pd_port, TCPC_TX_SOP,
- pd_port->mode_svid, pd_port->mode_obj_pos);
-}
-
-void pe_dfp_vdm_mode_entry_acked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_enter_mode(pd_port, pd_event, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dfp_vdm_mode_entry_naked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_enter_mode(pd_port, pd_event, false);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-69 DFP VDM Mode Exit State Diagram
- */
-
-void pe_dfp_vdm_mode_exit_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_vdm_exit_mode(pd_port, TCPC_TX_SOP,
- pd_port->mode_svid, pd_port->mode_obj_pos);
-}
-
-void pe_dfp_vdm_mode_exit_acked_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_dfp_inform_exit_mode(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-70 DFP VDM Attention State Diagram
- */
-
-void pe_dfp_vdm_attention_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_dfp_inform_attention(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for DR
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0]
- * Figure 8-53 Dual-Role (Source) Get Source Capabilities diagram
- * Figure 8-54 Dual-Role (Source) Give Sink Capabilities diagram
- * Figure 8-55 Dual-Role (Sink) Get Sink Capabilities State Diagram
- * Figure 8-56 Dual-Role (Sink) Give Source Capabilities State Diagram
- */
-
-void pe_dr_src_get_source_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_GET_SOURCE_CAP);
-}
-
-void pe_dr_src_get_source_cap_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- pd_dpm_dr_inform_source_cap(pd_port, pd_event);
-}
-
-void pe_dr_src_give_sink_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_send_sink_caps(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_dr_snk_get_sink_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_GET_SINK_CAP);
-}
-
-void pe_dr_snk_get_sink_cap_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- pd_dpm_dr_inform_sink_cap(pd_port, pd_event);
-}
-
-void pe_dr_snk_give_source_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_send_source_caps(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for DRS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-49: Type-C DFP to UFP Data Role Swap State Diagram
- */
-
-void pe_drs_dfp_ufp_evaluate_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_drs_evaluate_swap(pd_port, PD_ROLE_UFP);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_drs_dfp_ufp_accept_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-void pe_drs_dfp_ufp_change_to_ufp_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_drs_change_role(pd_port, PD_ROLE_UFP);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_drs_dfp_ufp_send_dr_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_DR_SWAP);
-}
-
-void pe_drs_dfp_ufp_reject_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg_sec == PD_DPM_NAK_REJECT)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- else
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
-}
-
-/*
- * [PD2.0] Figure 8-50: Type-C UFP to DFP Data Role Swap State Diagram
- */
-
-void pe_drs_ufp_dfp_evaluate_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_drs_evaluate_swap(pd_port, PD_ROLE_DFP);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_drs_ufp_dfp_accept_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-void pe_drs_ufp_dfp_change_to_dfp_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_drs_change_role(pd_port, PD_ROLE_DFP);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_drs_ufp_dfp_send_dr_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_DR_SWAP);
-}
-
-void pe_drs_ufp_dfp_reject_dr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg_sec == PD_DPM_NAK_REJECT)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- else
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for PRS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-51:
- * Dual-Role Port in Source to Sink Power Role Swap State Diagram
- */
-
-void pe_prs_src_snk_evaluate_pr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_prs_evaluate_swap(pd_port, PD_ROLE_SINK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_prs_src_snk_accept_pr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_notify_pe_execute_pr_swap(pd_port, true);
-
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-void pe_prs_src_snk_transition_to_off_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_lock_msg_output(pd_port); /* for tSRCTransition */
- pd_notify_pe_execute_pr_swap(pd_port, true);
-
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_TRANSITION);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_prs_src_snk_assert_rd_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_prs_change_role(pd_port, PD_ROLE_SINK);
-}
-
-void pe_prs_src_snk_wait_source_on_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PS_RDY);
-}
-
-void pe_prs_src_snk_wait_source_on_exit(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_PS_SOURCE_ON);
-}
-
-void pe_prs_src_snk_send_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PR_SWAP);
-}
-
-void pe_prs_src_snk_reject_pr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg_sec == PD_DPM_NAK_REJECT)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- else
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
-}
-
-/*
- * [PD2.0] Figure 8-52:
- * Dual-role Port in Sink to Source Power Role Swap State Diagram
- */
-
-void pe_prs_snk_src_evaluate_pr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_prs_evaluate_swap(pd_port, PD_ROLE_SOURCE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_prs_snk_src_accept_pr_swap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_notify_pe_execute_pr_swap(pd_port, true);
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-void pe_prs_snk_src_transition_to_off_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- /*
- * Sink should call pd_notify_pe_execute_pr_swap before this state,
- * because source may turn off power & change CC before we got
- * GoodCRC or Accept.
- */
-
- pd_port->during_swap = true;
- pd_enable_timer(pd_port, PD_TIMER_PS_SOURCE_OFF);
- pd_dpm_prs_turn_off_power_sink(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_prs_snk_src_transition_to_off_exit(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_PS_SOURCE_OFF);
-}
-
-void pe_prs_snk_src_assert_rp_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_prs_change_role(pd_port, PD_ROLE_SOURCE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_prs_snk_src_source_on_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_prs_enable_power_source(pd_port, true);
-}
-
-void pe_prs_snk_src_source_on_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
-/* Do it in process_event after source_on */
-/* pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PS_RDY); */
-}
-
-void pe_prs_snk_src_send_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_notify_pe_execute_pr_swap(pd_port, false);
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PR_SWAP);
-}
-
-void pe_prs_snk_src_reject_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg_sec == PD_DPM_NAK_REJECT)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- else
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for SNK
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-39 Sink Port state diagram
- */
-
-void pe_snk_startup_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u8 rx_cap = PD_RX_CAP_PE_STARTUP;
-
- pd_port->state_machine = PE_STATE_MACHINE_SINK;
- pd_reset_protocol_layer(pd_port);
-
- switch (pd_event->event_type) {
- case PD_EVT_HW_MSG: /* CC attached */
- pd_put_pe_event(pd_port, PD_PE_RESET_PRL_COMPLETED);
- break;
-
- case PD_EVT_PE_MSG: /* From Hard-Reset */
- pd_enable_vbus_valid_detection(pd_port, false);
- break;
-
- case PD_EVT_CTRL_MSG: /* From PR-SWAP (Received PS_RDY) */
- /* If we reset rx_cap in here, */
- /* maybe can't meet tSwapSink (Check it later) */
- if (!pd_dpm_check_vbus_valid(pd_port)) {
- PE_INFO("rx_cap_on\r\n");
- rx_cap = PD_RX_CAP_PE_SEND_WAIT_CAP;
- }
-
- pd_put_pe_event(pd_port, PD_PE_RESET_PRL_COMPLETED);
- pd_free_pd_event(pd_port, pd_event);
- break;
- }
-
- pd_set_rx_enable(pd_port, rx_cap);
-}
-
-void pe_snk_discovery_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#ifdef CONFIG_USB_PD_FAST_RESP_TYPEC_SRC
- pd_disable_timer(pd_port, PD_TIMER_SRC_RECOVER);
-#endif /* CONFIG_USB_PD_FAST_RESP_TYPEC_SRC */
- pd_enable_vbus_valid_detection(pd_port, true);
-}
-
-void pe_snk_wait_for_capabilities_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_notify_pe_hard_reset_completed(pd_port);
-
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_SEND_WAIT_CAP);
- pd_enable_timer(pd_port, PD_TIMER_SINK_WAIT_CAP);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_wait_for_capabilities_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SINK_WAIT_CAP);
-}
-
-void pe_snk_evaluate_capability_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- /* Stop NoResponseTimer and reset HardResetCounter to zero */
-
- pd_disable_timer(pd_port, PD_TIMER_NO_RESPONSE);
-
- pd_port->hard_reset_counter = 0;
- pd_port->pd_connected = 1;
- pd_port->pd_prev_connected = 1;
- pd_port->explicit_contract = false;
-
- pd_dpm_snk_evaluate_caps(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_select_capability_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg == PD_DPM_NOTIFIED) {
- PE_DBG("SelectCap%d, rdo:0x%08x\r\n",
- pd_event->msg_sec, pd_port->last_rdo);
- } else {
- /* new request, for debug only */
- /* pd_dpm_sink_vbus(pd_port, false); */
- PE_DBG("NewReq, rdo:0x%08x\r\n", pd_port->last_rdo);
- }
-
- pd_lock_msg_output(pd_port); /* SenderResponse */
- pd_send_data_msg(pd_port,
- TCPC_TX_SOP, PD_DATA_REQUEST, 1, &pd_port->last_rdo);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_select_capability_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
-
- if (pd_event_msg_match(pd_event,
- PD_EVT_CTRL_MSG, PD_CTRL_ACCEPT))
- pd_port->remote_selected_cap = RDO_POS(pd_port->last_rdo);
-
- /* Waiting for Hard-Reset Done */
- if (!pd_event_msg_match(pd_event,
- PD_EVT_TIMER_MSG, PD_TIMER_SENDER_RESPONSE))
- pd_unlock_msg_output(pd_port);
-}
-
-void pe_snk_transition_sink_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_timer(pd_port, PD_TIMER_PS_TRANSITION);
-
- if (pd_event->msg == PD_CTRL_GOTO_MIN) {
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_GIVE_BACK) {
- pd_port->request_i_new = pd_port->request_i_op;
- pd_dpm_snk_transition_power(pd_port, pd_event);
- }
- }
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_transition_sink_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event_msg_match(pd_event, PD_EVT_CTRL_MSG, PD_CTRL_PS_RDY))
- pd_dpm_snk_transition_power(pd_port, pd_event);
-
- pd_disable_timer(pd_port, PD_TIMER_PS_TRANSITION);
-}
-
-void pe_snk_ready_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event_msg_match(pd_event, PD_EVT_CTRL_MSG, PD_CTRL_WAIT))
- pd_enable_timer(pd_port, PD_TIMER_SINK_REQUEST);
-
- pd_port->state_machine = PE_STATE_MACHINE_SINK;
- pe_power_ready_entry(pd_port, pd_event);
-}
-
-void pe_snk_hard_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_hard_reset(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_transition_to_default_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reset_local_hw(pd_port);
- pd_dpm_snk_hard_reset(pd_port, pd_event);
-}
-
-void pe_snk_transition_to_default_exit(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_timer(pd_port, PD_TIMER_NO_RESPONSE);
-
-#ifdef CONFIG_USB_PD_FAST_RESP_TYPEC_SRC
- if (!pd_port->pd_prev_connected)
- pd_enable_timer(pd_port, PD_TIMER_SRC_RECOVER);
-#endif /* CONFIG_USB_PD_FAST_RESP_TYPEC_SRC */
-}
-
-void pe_snk_give_sink_cap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_send_sink_caps(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_get_source_cap_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_GET_SOURCE_CAP);
-}
-
-void pe_snk_send_soft_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_soft_reset(pd_port, PE_STATE_MACHINE_SINK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_snk_soft_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_handle_soft_reset(pd_port, PE_STATE_MACHINE_SINK);
- pd_free_pd_event(pd_port, pd_event);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for SRC
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-38 Source Port Policy Engine state diagram
- */
-
-void pe_src_startup_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->state_machine = PE_STATE_MACHINE_SOURCE;
-
- pd_port->cap_counter = 0;
- pd_port->request_i = -1;
- pd_port->request_v = TCPC_VBUS_SOURCE_5V;
-
- pd_reset_protocol_layer(pd_port);
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_STARTUP);
-
- switch (pd_event->event_type) {
- case PD_EVT_HW_MSG: /* CC attached */
- pd_enable_vbus_valid_detection(pd_port, true);
- break;
-
- case PD_EVT_PE_MSG: /* From Hard-Reset */
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_START);
- break;
-
- case PD_EVT_CTRL_MSG: /* From PR-SWAP (Received PS_RDY) */
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_START);
- break;
- }
-}
-
-void pe_src_discovery_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- /* MessageID Should be 0 for First SourceCap (Ellisys)... */
-
- /* The SourceCapabilitiesTimer continues to run during the states
- * defined in Source Startup Structured VDM Discover Identity State
- * Diagram
- */
-
- pd_port->msg_id_tx[TCPC_TX_SOP] = 0;
- pd_port->pd_connected = false;
-
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_CAPABILITY);
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- if (pd_is_auto_discover_cable_id(pd_port)) {
- pd_port->msg_id_tx[TCPC_TX_SOP_PRIME] = 0;
- pd_enable_timer(pd_port, PD_TIMER_DISCOVER_ID);
- }
-#endif
-}
-
-void pe_src_send_capabilities_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_SEND_WAIT_CAP);
-
- pd_dpm_send_source_caps(pd_port);
- pd_port->cap_counter++;
-
- pd_free_pd_event(pd_port, pd_event); /* soft-reset */
-}
-
-void pe_src_send_capabilities_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
-}
-
-void pe_src_negotiate_capabilities_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->pd_connected = true;
- pd_port->pd_prev_connected = true;
-
- pd_dpm_src_evaluate_request(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_transition_supply_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg == PD_DPM_PD_REQUEST) {
- pd_port->request_i_new = pd_port->request_i_op;
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_GOTO_MIN);
- } else {
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
- }
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_TRANSITION);
-}
-
-void pe_src_transition_supply_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SOURCE_TRANSITION);
-}
-
-void pe_src_transition_supply2_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PS_RDY);
-}
-
-void pe_src_ready_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->state_machine = PE_STATE_MACHINE_SOURCE;
- pd_notify_pe_src_explicit_contract(pd_port);
- pe_power_ready_entry(pd_port, pd_event);
-}
-
-void pe_src_disabled_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISABLE);
- pd_update_connect_state(pd_port, PD_CONNECT_TYPEC_ONLY);
-}
-
-void pe_src_capability_response_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg_sec) {
- case PD_DPM_NAK_REJECT_INVALID:
- pd_port->invalid_contract = true;
- case PD_DPM_NAK_REJECT:
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- break;
-
- case PD_DPM_NAK_WAIT:
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
- break;
- }
-}
-
-void pe_src_hard_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_hard_reset(pd_port);
-
- pd_free_pd_event(pd_port, pd_event);
- pd_enable_timer(pd_port, PD_TIMER_PS_HARD_RESET);
-}
-
-void pe_src_hard_reset_received_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_timer(pd_port, PD_TIMER_PS_HARD_RESET);
-}
-
-void pe_src_transition_to_default_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reset_local_hw(pd_port);
- pd_dpm_src_hard_reset(pd_port);
-}
-
-void pe_src_transition_to_default_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_enable_vconn(pd_port, true);
- pd_enable_timer(pd_port, PD_TIMER_NO_RESPONSE);
-}
-
-void pe_src_give_source_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_send_source_caps(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_get_sink_cap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_GET_SINK_CAP);
-}
-
-void pe_src_get_sink_cap_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- pd_dpm_dr_inform_sink_cap(pd_port, pd_event);
-}
-
-void pe_src_wait_new_capabilities_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- /* Wait for new Source Capabilities */
-}
-
-void pe_src_send_soft_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_soft_reset(pd_port, PE_STATE_MACHINE_SOURCE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_soft_reset_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_handle_soft_reset(pd_port, PE_STATE_MACHINE_SOURCE);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_ping_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- /* TODO: Send Ping Message */
-}
-
-/*
- * [PD2.0] Figure 8-81
- Source Startup Structured VDM Discover Identity State Diagram (TODO)
- */
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
-
-void pe_src_vdm_identity_request_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISCOVER_CABLE);
-
- pd_send_vdm_discover_id(pd_port, TCPC_TX_SOP_PRIME);
-
- pd_port->discover_id_counter++;
- pd_enable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_vdm_identity_acked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_port->dpm_flags &= ~DPM_FLAGS_CHECK_CABLE_ID;
-
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_src_inform_cable_vdo(pd_port, pd_event);
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_src_vdm_identity_naked_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VDM_RESPONSE);
- pd_dpm_src_inform_cable_vdo(pd_port, pd_event);
-
- pd_free_pd_event(pd_port, pd_event);
-}
-
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for UFP
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-58 UFP Structured VDM Discover Identity State Diagram
- */
-
-void pe_ufp_vdm_get_identity_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_request_id_info(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_send_identity_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_response_id(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_get_identity_nak_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_NAK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-59 UFP Structured VDM Discover SVIDs State Diagram
- */
-
-void pe_ufp_vdm_get_svids_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_request_svid_info(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_send_svids_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_response_svids(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_get_svids_nak_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_NAK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-60 UFP Structured VDM Discover Modes State Diagram
- */
-
-void pe_ufp_vdm_get_modes_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_request_mode_info(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_send_modes_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_response_modes(pd_port, pd_event);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_get_modes_nak_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_NAK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-61 UFP Structured VDM Enter Mode State Diagram
- */
-
-void pe_ufp_vdm_evaluate_mode_entry_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_request_enter_mode(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_mode_entry_ack_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_ACK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_mode_entry_nak_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_NAK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-62 UFP Structured VDM Exit Mode State Diagram
- */
-
-void pe_ufp_vdm_mode_exit_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_ufp_request_exit_mode(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_mode_exit_ack_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_ACK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_ufp_vdm_mode_exit_nak_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_reply_svdm_request_simply(pd_port, pd_event, CMDT_RSP_NAK);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-/*
- * [PD2.0] Figure 8-63 UFP VDM Attention State Diagram
- */
-
-void pe_ufp_vdm_attention_request_entry(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->mode_svid) {
- default:
- pd_send_vdm_attention(pd_port,
- TCPC_TX_SOP, pd_port->mode_svid,
- pd_port->mode_obj_pos);
- break;
- }
-
- pd_free_pd_event(pd_port, pd_event);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Policy Engine for VCS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-
-/*
- * [PD2.0] Figure 8-57 VCONN Swap State Diagram
- */
-
-void pe_vcs_send_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_VCONN_SWAP);
-}
-
-void pe_vcs_evaluate_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_vcs_evaluate_swap(pd_port);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_vcs_accept_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_ACCEPT);
-}
-
-void pe_vcs_reject_vconn_swap_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->msg_sec == PD_DPM_NAK_REJECT)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- else
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_WAIT);
-}
-
-void pe_vcs_wait_for_vconn_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_enable_timer(pd_port, PD_TIMER_VCONN_ON);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_vcs_wait_for_vconn_exit(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_disable_timer(pd_port, PD_TIMER_VCONN_ON);
-}
-
-void pe_vcs_turn_off_vconn_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_vcs_enable_vconn(pd_port, false);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_vcs_turn_on_vconn_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_dpm_vcs_enable_vconn(pd_port, true);
- pd_free_pd_event(pd_port, pd_event);
-}
-
-void pe_vcs_send_ps_rdy_entry(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PS_RDY);
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-
-/*
- * [BLOCK] print event
- */
-
-#if PE_EVENT_DBG_ENABLE
-static const char * const pd_ctrl_msg_name[] = {
- "ctrl0",
- "good_crc",
- "goto_min",
- "accept",
- "reject",
- "ping",
- "ps_rdy",
- "get_src_cap",
- "get_snk_cap",
- "dr_swap",
- "pr_swap",
- "vs_swap",
- "wait",
- "soft_reset",
- "ctrlE",
- "ctrlF",
-};
-
-static inline void print_ctrl_msg_event(u8 msg)
-{
- if (msg < PD_CTRL_MSG_NR)
- PE_EVT_INFO("%s\r\n", pd_ctrl_msg_name[msg]);
-}
-
-static const char * const pd_data_msg_name[] = {
- "data0",
- "src_cap",
- "request",
- "bist",
- "sink_cap",
- "data5",
- "data6",
- "data7",
- "data8",
- "data9",
- "dataA",
- "dataB",
- "dataC",
- "dataD",
- "dataE",
- "vdm",
-};
-
-static inline void print_data_msg_event(u8 msg)
-{
- if (msg < PD_DATA_MSG_NR)
- PE_EVT_INFO("%s\r\n", pd_data_msg_name[msg]);
-}
-
-static const char *const pd_hw_msg_name[] = {
- "Detached",
- "Attached",
- "hard_reset",
- "vbus_high",
- "vbus_low",
- "vbus_0v",
- "vbus_stable",
- "tx_err",
- "retry_vdm",
-};
-
-static inline void print_hw_msg_event(u8 msg)
-{
- if (msg < PD_HW_MSG_NR)
- PE_EVT_INFO("%s\r\n", pd_hw_msg_name[msg]);
-}
-
-static const char *const pd_pe_msg_name[] = {
- "reset_prl_done",
- "pr_at_dft",
- "hard_reset_done",
- "pe_idle",
-};
-
-static inline void print_pe_msg_event(u8 msg)
-{
- if (msg < PD_PE_MSG_NR)
- PE_EVT_INFO("%s\r\n", pd_pe_msg_name[msg]);
-}
-
-static const char * const pd_dpm_msg_name[] = {
- "ack",
- "nak",
-
- "pd_req",
- "vdm_req",
- "cable_req",
-
- "cap_change",
- "recover",
-};
-
-static inline void print_dpm_msg_event(u8 msg)
-{
- if (msg < PD_DPM_MSG_NR)
- PE_EVT_INFO("dpm_%s\r\n", pd_dpm_msg_name[msg]);
-}
-
-const char *const pd_dpm_pd_request_name[] = {
- "pr_swap",
- "dr_swap",
- "vs_swap",
- "gotomin",
- "softreset",
- "hardreset",
- "get_src_cap",
- "get_snk_cap",
- "request",
- "bist_cm2",
-};
-
-static inline void print_dpm_pd_request(u8 msg)
-{
- if (msg < PD_DPM_PD_REQUEST_NR)
- PE_EVT_INFO("dpm_pd_req(%s)\r\n", pd_dpm_pd_request_name[msg]);
-}
-#endif
-
-static inline void print_event(pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#if PE_EVENT_DBG_ENABLE
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- print_ctrl_msg_event(pd_event->msg);
- break;
-
- case PD_EVT_DATA_MSG:
- print_data_msg_event(pd_event->msg);
- break;
-
- case PD_EVT_DPM_MSG:
- if (pd_event->msg == PD_DPM_PD_REQUEST)
- print_dpm_pd_request(pd_event->msg_sec);
- else
- print_dpm_msg_event(pd_event->msg);
- break;
-
- case PD_EVT_HW_MSG:
- print_hw_msg_event(pd_event->msg);
- break;
-
- case PD_EVT_PE_MSG:
- print_pe_msg_event(pd_event->msg);
- break;
-
- case PD_EVT_TIMER_MSG:
- PE_EVT_INFO("timer\r\n");
- break;
- }
-#endif
-}
-
-bool pd_make_pe_state_transit(pd_port_t *pd_port,
- u8 curr_state,
- const pe_state_reaction_t *state_reaction)
-{
- int i;
- const pe_state_transition_t *state_transition =
- state_reaction->state_transition;
-
- for (i = 0; i < state_reaction->nr_transition; i++) {
- if (state_transition[i].curr_state == curr_state) {
- PE_TRANSIT_STATE(pd_port,
- state_transition[i].next_state);
- return true;
- }
- }
-
- return false;
-}
-
-bool pd_make_pe_state_transit_virt(pd_port_t *pd_port,
- u8 curr_state,
- const pe_state_reaction_t *state_reaction)
-{
- bool ret = pd_make_pe_state_transit(
- pd_port, curr_state, state_reaction);
-
- if (ret) {
- switch (pd_port->pe_state_next) {
- case PE_VIRT_READY:
- PE_TRANSIT_READY_STATE(pd_port);
- break;
-
- case PE_VIRT_HARD_RESET:
- PE_TRANSIT_HARD_RESET_STATE(pd_port);
- break;
- }
- }
- return ret;
-}
-
-bool pd_make_pe_state_transit_force(pd_port_t *pd_port,
- u8 curr_state, u8 force_state,
- const pe_state_reaction_t *state_reaction)
-{
- bool ret = pd_make_pe_state_transit(
- pd_port, curr_state, state_reaction);
-
- if (ret)
- return ret;
-
- PE_TRANSIT_STATE(pd_port, force_state);
- return true;
-}
-
-bool pd_process_protocol_error(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool power_change = false;
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- u8 event_type = pd_event->event_type;
- u8 msg_id = PD_HEADER_ID(pd_msg->msg_hdr);
- u8 msg_type = PD_HEADER_TYPE(pd_msg->msg_hdr);
-
- switch (pd_port->pe_state_curr) {
- case PE_SNK_TRANSITION_SINK:
- case PE_SRC_TRANSITION_SUPPLY:
- case PE_SRC_TRANSITION_SUPPLY2:
- power_change = true;
- case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
- if (pd_event_msg_match(pd_event,
- PD_EVT_CTRL_MSG, PD_CTRL_PING)) {
- PE_DBG("Igrone Ping\r\n");
- return false;
- }
- break;
-
- case PE_SRC_SOFT_RESET:
- case PE_SRC_SEND_SOFT_RESET:
- case PE_SNK_SOFT_RESET:
- case PE_SNK_SEND_SOFT_RESET:
- case PE_SNK_READY:
- case PE_SRC_READY:
- case PE_BIST_TEST_DATA:
- PE_DBG("Igrone Unknown Event\r\n");
- return false;
- };
-
- PE_INFO("PRL_ERR: %d-%d-%d\r\n", event_type, msg_type, msg_id);
-
- if (pd_port->during_swap)
- PE_TRANSIT_HARD_RESET_STATE(pd_port);
- else if (power_change)
- PE_TRANSIT_HARD_RESET_STATE(pd_port);
- else
- PE_TRANSIT_SEND_SOFT_RESET_STATE(pd_port);
- return true;
-}
-
-bool pd_process_data_msg_bist(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- if (pd_port->request_v > 5000) {
- PE_INFO("bist_not_vsafe5v\r\n");
- return false;
- }
-
- switch (BDO_MODE(pd_event->pd_msg->payload[0])) {
- case BDO_MODE_TEST_DATA:
- PE_DBG("bist_test\r\n");
- PE_TRANSIT_STATE(pd_port, PE_BIST_TEST_DATA);
- pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_TEST_DATA);
- return true;
-
- case BDO_MODE_CARRIER2:
- PE_DBG("bist_cm2\r\n");
- PE_TRANSIT_STATE(pd_port, PE_BIST_CARRIER_MODE_2);
- pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_DISABLE);
- return true;
-
- default:
- case BDO_MODE_RECV:
- case BDO_MODE_TRANSMIT:
- case BDO_MODE_COUNTERS:
- case BDO_MODE_CARRIER0:
- case BDO_MODE_CARRIER1:
- case BDO_MODE_CARRIER3:
- case BDO_MODE_EYE:
- PE_DBG("Unsupport BIST\r\n");
- pd_noitfy_pe_bist_mode(pd_port, PD_BIST_MODE_DISABLE);
- return false;
- }
-
- return false;
-}
-
-/* DRP (Data Role Swap) */
-
-bool pd_process_ctrl_msg_dr_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool reject;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- reject = !(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA);
-
- if (!reject) {
- if (pd_port->data_role == PD_ROLE_DFP)
- reject = pd_port->dpm_caps &
- DPM_CAP_DR_SWAP_REJECT_AS_UFP;
- else
- reject = pd_port->dpm_caps &
- DPM_CAP_DR_SWAP_REJECT_AS_DFP;
- }
-
- if (reject) {
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- return false;
- }
- if (pd_port->modal_operation) {
- PE_TRANSIT_HARD_RESET_STATE(pd_port);
- } else {
- pd_port->during_swap = false;
- pd_port->state_machine = PE_STATE_MACHINE_DR_SWAP;
-
- PE_TRANSIT_DATA_STATE(pd_port,
- PE_DRS_UFP_DFP_EVALUATE_DR_SWAP,
- PE_DRS_DFP_UFP_EVALUATE_DR_SWAP);
- }
- return true;
-}
-
-bool pd_process_dpm_msg_dr_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_DATA))
- return false;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- pd_port->during_swap = false;
- pd_port->state_machine = PE_STATE_MACHINE_DR_SWAP;
-
- PE_TRANSIT_DATA_STATE(pd_port,
- PE_DRS_UFP_DFP_SEND_DR_SWAP,
- PE_DRS_DFP_UFP_SEND_DR_SWAP);
-
- return true;
-}
-
-/* DRP (Power Role Swap) */
-
-bool pd_process_ctrl_msg_pr_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool reject;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- reject = !(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER);
-
- if (!reject) {
- if (pd_port->power_role == PD_ROLE_SOURCE)
- reject = pd_port->dpm_caps &
- DPM_CAP_PR_SWAP_REJECT_AS_SNK;
- else
- reject = pd_port->dpm_caps &
- DPM_CAP_PR_SWAP_REJECT_AS_SRC;
- }
-
- if (reject) {
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- return false;
- }
- pd_port->during_swap = false;
- pd_port->state_machine = PE_STATE_MACHINE_PR_SWAP;
-
- PE_TRANSIT_POWER_STATE(pd_port,
- PE_PRS_SNK_SRC_EVALUATE_PR_SWAP,
- PE_PRS_SRC_SNK_EVALUATE_PR_SWAP);
-
- return true;
-}
-
-bool pd_process_dpm_msg_pr_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER))
- return false;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- pd_port->during_swap = false;
- pd_port->state_machine = PE_STATE_MACHINE_PR_SWAP;
-
- PE_TRANSIT_POWER_STATE(pd_port,
- PE_PRS_SNK_SRC_SEND_SWAP,
- PE_PRS_SRC_SNK_SEND_SWAP);
- return true;
-}
-
-/* DRP (Vconn Swap) */
-
-bool pd_process_ctrl_msg_vconn_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_VCONN_SUPPLY)) {
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- return false;
- }
- pd_port->state_machine = PE_STATE_MACHINE_VCONN_SWAP;
- PE_TRANSIT_STATE(pd_port, PE_VCS_EVALUATE_SWAP);
- return true;
-}
-
-bool pd_process_dpm_msg_vconn_swap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!(pd_port->dpm_caps & DPM_CAP_LOCAL_VCONN_SUPPLY))
- return false;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- pd_port->state_machine = PE_STATE_MACHINE_VCONN_SWAP;
- PE_TRANSIT_STATE(pd_port, PE_VCS_SEND_SWAP);
- return true;
-}
-
-bool pd_process_recv_hard_reset(
- pd_port_t *pd_port, pd_event_t *pd_event, u8 hreset_state)
-{
- PE_TRANSIT_STATE(pd_port, hreset_state);
- return true;
-}
-
-bool pd_process_dpm_msg_pw_request(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr != PE_SNK_READY)
- return false;
-
- PE_TRANSIT_STATE(pd_port, PE_SNK_SELECT_CAPABILITY);
- return true;
-}
-
-bool pd_process_dpm_msg_bist_cm2(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u32 bist = BDO_MODE_CARRIER2;
-
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- pd_send_data_msg(pd_port, TCPC_TX_SOP, PD_DATA_BIST, 1, &bist);
- return false;
-}
-
-bool pd_process_dpm_msg_gotomin(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr != PE_SRC_READY)
- return false;
-
- if (!(pd_port->dpm_flags & DPM_CAP_LOCAL_GIVE_BACK))
- return false;
-
- PE_TRANSIT_STATE(pd_port, PE_SRC_TRANSITION_SUPPLY);
- return true;
-}
-
-bool pd_process_dpm_msg_softreset(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- PE_TRANSIT_SEND_SOFT_RESET_STATE(pd_port);
- return true;
-}
-
-bool pd_process_dpm_msg_hardreset(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!pd_check_pe_state_ready(pd_port))
- return false;
-
- PE_TRANSIT_HARD_RESET_STATE(pd_port);
- return true;
-}
-
-bool pd_process_dpm_msg_get_source_cap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SNK_READY:
- PE_TRANSIT_STATE(pd_port, PE_SNK_GET_SOURCE_CAP);
- return true;
-
- case PE_SRC_READY:
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
- PE_TRANSIT_STATE(pd_port, PE_DR_SRC_GET_SOURCE_CAP);
- return true;
- }
- break;
- }
-
- return false;
-}
-
-bool pd_process_dpm_msg_get_sink_cap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SRC_READY:
- PE_TRANSIT_STATE(pd_port, PE_SRC_GET_SINK_CAP);
- return true;
-
- case PE_SNK_READY:
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
- PE_TRANSIT_STATE(pd_port, PE_DR_SNK_GET_SINK_CAP);
- return true;
- }
- break;
- }
-
- return false;
-}
-
-bool pd_process_event_dpm_pd_request(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg_sec) {
- case PD_DPM_PD_REQUEST_PR_SWAP:
- ret = pd_process_dpm_msg_pr_swap(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_DR_SWAP:
- ret = pd_process_dpm_msg_dr_swap(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_VCONN_SWAP:
- ret = pd_process_dpm_msg_vconn_swap(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_GOTOMIN:
- ret = pd_process_dpm_msg_gotomin(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_SOFTRESET:
- ret = pd_process_dpm_msg_softreset(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_HARDRESET:
- ret = pd_process_dpm_msg_hardreset(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_GET_SOURCE_CAP:
- ret = pd_process_dpm_msg_get_source_cap(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_GET_SINK_CAP:
- ret = pd_process_dpm_msg_get_sink_cap(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_PW_REQUEST:
- ret = pd_process_dpm_msg_pw_request(pd_port, pd_event);
- break;
-
- case PD_DPM_PD_REQUEST_BIST_CM2:
- ret = pd_process_dpm_msg_bist_cm2(pd_port, pd_event);
- break;
-
- default:
- PE_DBG("Unknown PD_Request\r\n");
- return false;
- }
-
- if (!ret)
- /* TODO: Notify DPM, Policy Engine Reject this request ... */
- PE_DBG("Reject DPM PD Request\r\n");
- return ret;
-}
-
-/* @ true : valid message */
-/* @ false : invalid message, pe should drop the message */
-
-static inline bool pe_is_valid_pd_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- u8 event_type = pd_event->event_type;
- u8 sop_type = pd_msg->frame_type;
- u8 msg_id = PD_HEADER_ID(pd_msg->msg_hdr);
- u8 msg_type = PD_HEADER_TYPE(pd_msg->msg_hdr);
-
- if (pd_port->pe_state_curr == PE_BIST_TEST_DATA)
- return false;
-
- if (event_type == PD_EVT_CTRL_MSG) {
- switch (msg_type) {
- /* SofReset always has a MessageID value of zero */
- case PD_CTRL_SOFT_RESET:
- if (msg_id != 0) {
- PE_INFO("Repeat soft_reset\r\n");
- return false;
- }
-
- return true;
- case PD_CTRL_GOOD_CRC:
- PE_DBG("Discard_CRC\r\n");
- return true;
- }
- }
-
- if ((pd_port->msg_id_rx_init[sop_type]) &&
- (pd_port->msg_id_rx[sop_type] == msg_id)) {
- PE_INFO("Repeat msg: %c:%d:%d\r\n",
- (pd_event->event_type == PD_EVT_CTRL_MSG) ? 'C' : 'D',
- pd_event->msg, msg_id);
- return false;
- }
-
- pd_port->msg_id_rx[sop_type] = msg_id;
- pd_port->msg_id_rx_init[sop_type] = true;
-
- return true;
-}
-
-static inline bool pe_is_valid_pd_msg_role(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = true;
- u8 msg_pr, msg_dr;
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- if (!pd_msg) /* Good-CRC */
- return true;
-
- if (pd_msg->frame_type != TCPC_TX_SOP)
- return true;
-
- msg_pr = PD_HEADER_PR(pd_msg->msg_hdr);
- msg_dr = PD_HEADER_DR(pd_msg->msg_hdr);
-
- /*
- * The Port Power Role field of a received Message shall not be verified
- * by the receiver and no error recovery action shall be
- * taken if it is incorrect.
- */
-
- if (msg_pr == pd_port->power_role)
- PE_DBG("Wrong PR:%d\r\n", msg_pr);
-
- /*
- * Should a Type-C Port receive a Message with the Port Data Role field
- * set to the same Data Role as its current Data Role,
- * except for the GoodCRC Message,
- * Type-C error recovery actions as defined
- * in [USBType-C 1.0] shall be performed.
- */
-
- if (msg_dr == pd_port->data_role)
- PE_INFO("Wrong DR:%d\r\n", msg_dr);
-
- return ret;
-}
-
-static inline bool pe_translate_pd_msg_event(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- pd_msg_t *pd_msg;
-
- if (pd_event->event_type != PD_EVT_PD_MSG)
- return true;
-
- pd_msg = pd_event->pd_msg;
-
- if (PD_HEADER_CNT(pd_msg->msg_hdr))
- pd_event->event_type = PD_EVT_DATA_MSG;
- else
- pd_event->event_type = PD_EVT_CTRL_MSG;
-
- pd_event->msg = PD_HEADER_TYPE(pd_msg->msg_hdr);
-
- return pe_is_valid_pd_msg(pd_port, pd_event);
-}
-
-static inline bool pe_exit_idle_state(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- pd_port->custom_dbgacc = false;
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
-
- switch (pd_event->msg_sec) {
- case TYPEC_ATTACHED_SNK:
- pd_init_role(pd_port,
- PD_ROLE_SINK, PD_ROLE_UFP, PD_ROLE_VCONN_OFF);
- break;
-
- case TYPEC_ATTACHED_SRC:
- pd_init_role(pd_port,
- PD_ROLE_SOURCE, PD_ROLE_DFP, PD_ROLE_VCONN_ON);
- break;
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- case TYPEC_ATTACHED_DBGACC_SNK:
- pd_port->custom_dbgacc = true;
- pd_init_role(pd_port,
- PD_ROLE_SINK, PD_ROLE_UFP, PD_ROLE_VCONN_OFF);
- break;
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
-
- default:
- return false;
- }
-
- pd_port->cap_counter = 0;
- pd_port->discover_id_counter = 0;
- pd_port->hard_reset_counter = 0;
- pd_port->get_snk_cap_count = 0;
- pd_port->get_src_cap_count = 0;
-
- pd_port->pe_ready = 0;
- pd_port->pd_connected = 0;
- pd_port->pd_prev_connected = 0;
- pd_port->reset_vdm_state = 0;
- pd_port->power_cable_present = 0;
-
- pd_port->explicit_contract = false;
- pd_port->invalid_contract = false;
-
- pd_port->modal_operation = false;
- pd_port->during_swap = false;
- pd_port->dpm_ack_immediately = false;
-
- pd_port->remote_src_cap.nr = 0;
- pd_port->remote_snk_cap.nr = 0;
-
- memset(pd_port->cable_vdos, 0, sizeof(uint32_t) * VDO_MAX_SIZE);
-
- pd_dpm_notify_pe_startup(pd_port);
- return true;
-}
-
-static inline bool pe_is_trap_in_idle_state(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool trap = true;
-
- switch (pd_port->pe_state_curr) {
- case PE_IDLE1:
- if (pd_event_msg_match(pd_event, PD_EVT_PE_MSG, PD_PE_IDLE))
- return false;
- pd_try_put_pe_idle_event(pd_port);
- case PE_IDLE2:
- break;
-
- default:
- return false;
- }
-
- if (pd_event->event_type == PD_EVT_HW_MSG) {
- switch (pd_event->msg) {
- case PD_HW_CC_ATTACHED:
- trap = false;
- break;
-
- case PD_HW_CC_DETACHED:
- pd_notify_pe_idle(pd_port);
- break;
-
- default:
- break;
- }
- }
-
- if (!trap)
- trap = !pe_exit_idle_state(pd_port, pd_event);
- return trap;
-}
-
-bool pd_process_event(pd_port_t *pd_port, pd_event_t *pd_event, bool vdm_evt)
-{
- bool ret = false;
-
- if (pe_is_trap_in_idle_state(pd_port, pd_event)) {
- PE_DBG("Trap in idle state, Igrone All MSG\r\n");
- return false;
- }
-
- if (!pe_translate_pd_msg_event(pd_port, pd_event))
- return false;
-
-#if PE_EVT_INFO_VDM_DIS
- if (!vdm_evt)
-#endif
- print_event(pd_port, pd_event);
-
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- case PD_EVT_DATA_MSG:
- if (!pe_is_valid_pd_msg_role(pd_port, pd_event)) {
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- return true;
- }
- break;
- }
-
- if (vdm_evt)
- return pd_process_event_vdm(pd_port, pd_event);
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
- if (pd_port->custom_dbgacc)
- return pd_process_event_dbg(pd_port, pd_event);
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
-
- if ((pd_event->event_type == PD_EVT_CTRL_MSG) &&
- (pd_event->msg != PD_CTRL_GOOD_CRC) &&
- (pd_event->pd_msg->frame_type != TCPC_TX_SOP)) {
- PE_DBG("Igrone not SOP Ctrl Msg\r\n");
- return false;
- }
-
- if (pd_event_msg_match(pd_event, PD_EVT_DPM_MSG, PD_DPM_PD_REQUEST))
- return pd_process_event_dpm_pd_request(pd_port, pd_event);
-
- switch (pd_port->state_machine) {
- case PE_STATE_MACHINE_DR_SWAP:
- ret = pd_process_event_drs(pd_port, pd_event);
- break;
- case PE_STATE_MACHINE_PR_SWAP:
- ret = pd_process_event_prs(pd_port, pd_event);
- break;
- case PE_STATE_MACHINE_VCONN_SWAP:
- ret = pd_process_event_vcs(pd_port, pd_event);
- break;
- }
-
- if (ret)
- return true;
-
- if (pd_port->power_role == PD_ROLE_SINK)
- ret = pd_process_event_snk(pd_port, pd_event);
- else
- ret = pd_process_event_src(pd_port, pd_event);
-
- return ret;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For DBGACC
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-
-#ifdef CONFIG_USB_PD_CUSTOM_DBGACC
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_IDLE) = {
- { PE_IDLE1, PE_IDLE2 },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_IDLE);
-
-bool pd_process_event_dbg(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_event->event_type == PD_EVT_HW_MSG) {
- switch (pd_event->msg) {
- case PD_HW_CC_DETACHED:
- PE_TRANSIT_STATE(pd_port, PE_IDLE1);
- return true;
-
- case PD_HW_CC_ATTACHED:
- PE_TRANSIT_STATE(pd_port, PE_DBG_READY);
- return true;
- }
- }
-
- if (pd_event_msg_match(pd_event, PD_EVT_PE_MSG, PD_PE_IDLE))
- return PE_MAKE_STATE_TRANSIT(PD_PE_MSG_IDLE);
-
- return false;
-}
-
-#endif /* CONFIG_USB_PD_CUSTOM_DBGACC */
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For DRS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-
-/* PD Control MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
- { PE_DRS_DFP_UFP_SEND_DR_SWAP, PE_DRS_DFP_UFP_CHANGE_TO_UFP },
- { PE_DRS_UFP_DFP_SEND_DR_SWAP, PE_DRS_UFP_DFP_CHANGE_TO_DFP },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_REJECT_WAIT) = {
- { PE_DRS_DFP_UFP_SEND_DR_SWAP, PE_VIRT_READY },
- { PE_DRS_UFP_DFP_SEND_DR_SWAP, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_REJECT_WAIT);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_DRS_DFP_UFP_EVALUATE_DR_SWAP, PE_DRS_DFP_UFP_ACCEPT_DR_SWAP },
- { PE_DRS_UFP_DFP_EVALUATE_DR_SWAP, PE_DRS_UFP_DFP_ACCEPT_DR_SWAP },
- { PE_DRS_DFP_UFP_CHANGE_TO_UFP, PE_VIRT_READY },
- { PE_DRS_UFP_DFP_CHANGE_TO_DFP, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
- { PE_DRS_DFP_UFP_EVALUATE_DR_SWAP, PE_DRS_DFP_UFP_REJECT_DR_SWAP },
- { PE_DRS_UFP_DFP_EVALUATE_DR_SWAP, PE_DRS_UFP_DFP_REJECT_DR_SWAP },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SENDER_RESPONSE) = {
- { PE_DRS_DFP_UFP_SEND_DR_SWAP, PE_VIRT_READY },
- { PE_DRS_UFP_DFP_SEND_DR_SWAP, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SENDER_RESPONSE);
-
-/*
- * [BLOCK] Porcess PD Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_DRS_DFP_UFP_REJECT_DR_SWAP:
- case PE_DRS_UFP_DFP_REJECT_DR_SWAP:
- PE_TRANSIT_READY_STATE(pd_port);
- return true;
-
- case PE_DRS_DFP_UFP_ACCEPT_DR_SWAP:
- PE_TRANSIT_STATE(pd_port, PE_DRS_DFP_UFP_CHANGE_TO_UFP);
- return true;
-
- case PE_DRS_UFP_DFP_ACCEPT_DR_SWAP:
- PE_TRANSIT_STATE(pd_port, PE_DRS_UFP_DFP_CHANGE_TO_DFP);
- return true;
-
- case PE_DRS_DFP_UFP_SEND_DR_SWAP:
- case PE_DRS_UFP_DFP_SEND_DR_SWAP:
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- return false;
-
- default:
- return false;
- }
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- case PD_CTRL_ACCEPT:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
-
- case PD_CTRL_WAIT:
- case PD_CTRL_REJECT:
- return PE_MAKE_STATE_TRANSIT_VIRT(PD_CTRL_MSG_REJECT_WAIT);
-
- default:
- return false;
- }
-}
-
-/*
- * [BLOCK] Porcess DPM MSG
- */
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_DPM_MSG_ACK);
- break;
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_TIMER_SENDER_RESPONSE:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_TIMER_SENDER_RESPONSE);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Process Policy Engine's DRS Message
- */
-
-bool pd_process_event_drs(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
-
- default:
- return false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For PRS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-
-/* PD Control MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOOD_CRC) = {
- { PE_PRS_SRC_SNK_ACCEPT_PR_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF },
- { PE_PRS_SRC_SNK_REJECT_PR_SWAP, PE_SRC_READY },
-
- { PE_PRS_SNK_SRC_ACCEPT_PR_SWAP, PE_PRS_SNK_SRC_TRANSITION_TO_OFF },
- { PE_PRS_SNK_SRC_REJECT_SWAP, PE_SNK_READY },
-
- /* VBUS-ON & PS_RDY SENT */
- { PE_PRS_SNK_SRC_SOURCE_ON, PE_SRC_STARTUP },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOOD_CRC);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
- { PE_PRS_SRC_SNK_SEND_SWAP, PE_PRS_SRC_SNK_TRANSITION_TO_OFF },
- { PE_PRS_SNK_SRC_SEND_SWAP, PE_PRS_SNK_SRC_TRANSITION_TO_OFF },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_REJECT_WAIT) = {
- { PE_PRS_SRC_SNK_SEND_SWAP, PE_SRC_READY },
- { PE_PRS_SNK_SRC_SEND_SWAP, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_REJECT_WAIT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_PS_RDY) = {
- { PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_SNK_STARTUP },
- { PE_PRS_SNK_SRC_TRANSITION_TO_OFF, PE_PRS_SNK_SRC_ASSERT_RP },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_PS_RDY);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_PRS_SRC_SNK_EVALUATE_PR_SWAP, PE_PRS_SRC_SNK_ACCEPT_PR_SWAP },
- { PE_PRS_SNK_SRC_EVALUATE_PR_SWAP, PE_PRS_SNK_SRC_ACCEPT_PR_SWAP },
-
- { PE_PRS_SRC_SNK_ASSERT_RD, PE_PRS_SRC_SNK_WAIT_SOURCE_ON },
- { PE_PRS_SNK_SRC_ASSERT_RP, PE_PRS_SNK_SRC_SOURCE_ON },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
- { PE_PRS_SRC_SNK_EVALUATE_PR_SWAP, PE_PRS_SRC_SNK_REJECT_PR_SWAP },
- { PE_PRS_SNK_SRC_EVALUATE_PR_SWAP, PE_PRS_SNK_SRC_REJECT_SWAP },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-/* HW Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_HW_TX_FAILED) = {
- { PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_SNK_HARD_RESET },
- { PE_PRS_SNK_SRC_SOURCE_ON, PE_SRC_HARD_RESET },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_TX_FAILED);
-
-DECL_PE_STATE_TRANSITION(PD_HW_VBUS_SAFE0V) = {
- { PE_PRS_SRC_SNK_TRANSITION_TO_OFF, PE_PRS_SRC_SNK_ASSERT_RD },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_VBUS_SAFE0V);
-
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SENDER_RESPONSE) = {
- { PE_PRS_SRC_SNK_SEND_SWAP, PE_SRC_READY },
- { PE_PRS_SNK_SRC_SEND_SWAP, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SENDER_RESPONSE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_PS_SOURCE_ON) = {
- { PE_PRS_SRC_SNK_WAIT_SOURCE_ON, PE_SNK_HARD_RESET },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_PS_SOURCE_ON);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_PS_SOURCE_OFF) = {
- { PE_PRS_SNK_SRC_TRANSITION_TO_OFF, PE_SNK_HARD_RESET },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_PS_SOURCE_OFF);
-
-/*
- * [BLOCK] Porcess PD Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
- pd_enable_timer(pd_port, PD_TIMER_PS_SOURCE_ON);
- pd_unlock_msg_output(pd_port); /* for tSRCTransition */
- return false;
-
- case PE_PRS_SRC_SNK_SEND_SWAP:
- case PE_PRS_SNK_SRC_SEND_SWAP:
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- return false;
-
- default:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOOD_CRC);
- }
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- case PD_CTRL_ACCEPT:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
-
- case PD_CTRL_WAIT:
- case PD_CTRL_REJECT:
- pd_notify_pe_cancel_pr_swap(pd_port);
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_REJECT_WAIT);
-
- case PD_CTRL_PS_RDY:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_PS_RDY);
-
- default:
- return false;
- }
-}
-
-/*
- * [BLOCK] Porcess DPM MSG
- */
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_DPM_MSG_ACK);
- break;
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess HW MSG
- */
-
-static inline bool pd_process_hw_msg_vbus_present(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr == PE_PRS_SNK_SRC_SOURCE_ON)
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_PS_RDY);
-
- return false;
-}
-
-static inline bool pd_process_hw_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_HW_VBUS_PRESENT:
- return pd_process_hw_msg_vbus_present(pd_port, pd_event);
-
- case PD_HW_TX_FAILED:
- return PE_MAKE_STATE_TRANSIT(PD_HW_TX_FAILED);
-
- case PD_HW_VBUS_SAFE0V:
- return PE_MAKE_STATE_TRANSIT(PD_HW_VBUS_SAFE0V);
-
- default:
- return false;
- }
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_TIMER_SENDER_RESPONSE:
- pd_notify_pe_cancel_pr_swap(pd_port);
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_SENDER_RESPONSE);
-
- case PD_TIMER_PS_SOURCE_ON:
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_PS_SOURCE_ON);
-
- case PD_TIMER_PS_SOURCE_OFF:
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_PS_SOURCE_OFF);
-
- case PD_TIMER_SOURCE_TRANSITION:
- pd_dpm_prs_enable_power_source(pd_port, false);
- return false;
- default:
- return false;
- }
-}
-
-/*
- * [BLOCK] Process Policy Engine's PRS Message
- */
-
-bool pd_process_event_prs(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_HW_MSG:
- return pd_process_hw_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
-
- default:
- return false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For SNK
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-
-/* PD Control MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOOD_CRC) = {
- /* sink */
- { PE_SNK_GIVE_SINK_CAP, PE_SNK_READY },
- { PE_SNK_GET_SOURCE_CAP, PE_SNK_READY },
-
- { PE_SNK_SOFT_RESET, PE_SNK_WAIT_FOR_CAPABILITIES },
-
- /* dual */
- { PE_DR_SNK_GIVE_SOURCE_CAP, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOOD_CRC);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOTO_MIN) = {
- { PE_SNK_READY, PE_SNK_TRANSITION_SINK },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOTO_MIN);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
- { PE_SNK_SELECT_CAPABILITY, PE_SNK_TRANSITION_SINK },
- { PE_SNK_SEND_SOFT_RESET, PE_SNK_WAIT_FOR_CAPABILITIES },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_PS_RDY) = {
- { PE_SNK_TRANSITION_SINK, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_PS_RDY);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GET_SINK_CAP) = {
- { PE_SNK_READY, PE_SNK_GIVE_SINK_CAP },
-
- { PE_SNK_GET_SOURCE_CAP, PE_SNK_GIVE_SINK_CAP },
- { PE_DR_SNK_GET_SINK_CAP, PE_SNK_GIVE_SINK_CAP },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GET_SINK_CAP);
-
-/* PD Data MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DATA_MSG_SOURCE_CAP) = {
- { PE_SNK_WAIT_FOR_CAPABILITIES, PE_SNK_EVALUATE_CAPABILITY },
- { PE_SNK_READY, PE_SNK_EVALUATE_CAPABILITY },
-
- /* PR-Swap issue (Check it later) */
- { PE_SNK_STARTUP, PE_SNK_EVALUATE_CAPABILITY },
- { PE_SNK_DISCOVERY, PE_SNK_EVALUATE_CAPABILITY },
-};
-
-DECL_PE_STATE_REACTION(PD_DATA_MSG_SOURCE_CAP);
-
-DECL_PE_STATE_TRANSITION(PD_DATA_MSG_SINK_CAP) = {
- { PE_DR_SNK_GET_SINK_CAP, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_DATA_MSG_SINK_CAP);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_SNK_EVALUATE_CAPABILITY, PE_SNK_SELECT_CAPABILITY },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-/* HW Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_HW_MSG_VBUS_PRESENT) = {
- { PE_SNK_DISCOVERY, PE_SNK_WAIT_FOR_CAPABILITIES},
-};
-
-DECL_PE_STATE_REACTION(PD_HW_MSG_VBUS_PRESENT);
-
-DECL_PE_STATE_TRANSITION(PD_HW_MSG_VBUS_ABSENT) = {
- { PE_SNK_STARTUP, PE_SNK_DISCOVERY },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_MSG_VBUS_ABSENT);
-
-DECL_PE_STATE_TRANSITION(PD_HW_MSG_TX_FAILED) = {
- { PE_SNK_SOFT_RESET, PE_SNK_HARD_RESET },
- { PE_SNK_SEND_SOFT_RESET, PE_SNK_HARD_RESET },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_MSG_TX_FAILED);
-
-/* PE Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_HARD_RESET_COMPLETED) = {
- { PE_SNK_HARD_RESET, PE_SNK_TRANSITION_TO_DEFAULT },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_HARD_RESET_COMPLETED);
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_RESET_PRL_COMPLETED) = {
- { PE_SNK_STARTUP, PE_SNK_DISCOVERY },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_RESET_PRL_COMPLETED);
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_POWER_ROLE_AT_DEFAULT) = {
- { PE_SNK_TRANSITION_TO_DEFAULT, PE_SNK_STARTUP },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_POWER_ROLE_AT_DEFAULT);
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_IDLE) = {
- { PE_IDLE1, PE_IDLE2 },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_IDLE);
-
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_BIST_CONT_MODE) = {
- { PE_BIST_CARRIER_MODE_2, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_BIST_CONT_MODE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SENDER_RESPONSE) = {
- { PE_SNK_SELECT_CAPABILITY, PE_SNK_HARD_RESET },
- { PE_SNK_SEND_SOFT_RESET, PE_SNK_HARD_RESET },
-
- { PE_DR_SNK_GET_SINK_CAP, PE_SNK_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SENDER_RESPONSE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SINK_REQUEST) = {
- { PE_SNK_READY, PE_SNK_SELECT_CAPABILITY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SINK_REQUEST);
-
-/*
- * [BLOCK] Porcess Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SNK_SELECT_CAPABILITY:
- case PE_SNK_SEND_SOFT_RESET:
- case PE_DR_SNK_GET_SINK_CAP:
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- return false;
-
- default:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOOD_CRC);
- }
-}
-
-static inline bool pd_process_ctrl_msg_get_source_cap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SNK_READY:
- case PE_DR_SNK_GET_SINK_CAP:
- case PE_SNK_GET_SOURCE_CAP:
- break;
-
- default:
- return false;
- }
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
- PE_TRANSIT_STATE(pd_port, PE_DR_SNK_GIVE_SOURCE_CAP);
- return true;
- }
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- return false;
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- case PD_CTRL_GOTO_MIN:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOTO_MIN);
- break;
-
- case PD_CTRL_ACCEPT:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
- break;
-
- case PD_CTRL_PING:
- pd_notify_pe_recv_ping_event(pd_port);
- break;
-
- case PD_CTRL_PS_RDY:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_PS_RDY);
- break;
-
- case PD_CTRL_GET_SOURCE_CAP:
- ret = pd_process_ctrl_msg_get_source_cap(pd_port, pd_event);
- break;
-
- case PD_CTRL_GET_SINK_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GET_SINK_CAP);
- break;
-
- case PD_CTRL_REJECT:
- if (pd_port->pe_state_curr == PE_DR_SNK_GET_SINK_CAP) {
- PE_TRANSIT_STATE(pd_port, PE_SNK_READY);
- return true;
- }
- /* no break!*/
-
- case PD_CTRL_WAIT:
- if (pd_port->pe_state_curr == PE_SNK_SELECT_CAPABILITY) {
- if (pd_port->explicit_contract)
- PE_TRANSIT_STATE(pd_port, PE_SNK_READY);
- else
- PE_TRANSIT_STATE(pd_port,
- PE_SNK_WAIT_FOR_CAPABILITIES);
-
- return true;
- }
- break;
-
- /* Swap */
- case PD_CTRL_DR_SWAP:
- ret = pd_process_ctrl_msg_dr_swap(pd_port, pd_event);
- break;
-
- case PD_CTRL_PR_SWAP:
- ret = pd_process_ctrl_msg_pr_swap(pd_port, pd_event);
- break;
-
- case PD_CTRL_VCONN_SWAP:
- ret = pd_process_ctrl_msg_vconn_swap(pd_port, pd_event);
- break;
-
- /* SoftReset */
- case PD_CTRL_SOFT_RESET:
- if (!pd_port->during_swap) {
- PE_TRANSIT_STATE(pd_port, PE_SNK_SOFT_RESET);
- return true;
- }
- break;
- }
-
- if (!ret)
- ret = pd_process_protocol_error(pd_port, pd_event);
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Data MSG
- */
-
-static inline bool pd_process_data_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DATA_SOURCE_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_SOURCE_CAP);
- break;
-
- case PD_DATA_SINK_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_SINK_CAP);
- break;
-
- case PD_DATA_BIST:
- ret = pd_process_data_msg_bist(pd_port, pd_event);
- break;
-
- case PD_DATA_REQUEST:
- case PD_DATA_VENDOR_DEF:
- break;
- }
-
- if (!ret)
- ret = pd_process_protocol_error(pd_port, pd_event);
- return ret;
-}
-
-/*
- * [BLOCK] Porcess DPM MSG
- */
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
- break;
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
- case PD_DPM_ERROR_RECOVERY:
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- return true;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess HW MSG
- */
-
-static inline bool pd_process_hw_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_HW_CC_DETACHED:
- PE_TRANSIT_STATE(pd_port, PE_IDLE1);
- return true;
-
- case PD_HW_CC_ATTACHED:
- PE_TRANSIT_STATE(pd_port, PE_SNK_STARTUP);
- return true;
-
- case PD_HW_RECV_HARD_RESET:
- ret = pd_process_recv_hard_reset(
- pd_port, pd_event, PE_SNK_TRANSITION_TO_DEFAULT);
- break;
-
- case PD_HW_VBUS_PRESENT:
- ret = PE_MAKE_STATE_TRANSIT(PD_HW_MSG_VBUS_PRESENT);
- break;
-
- case PD_HW_VBUS_ABSENT:
- ret = PE_MAKE_STATE_TRANSIT(PD_HW_MSG_VBUS_ABSENT);
- break;
-
- case PD_HW_TX_FAILED:
- ret = PE_MAKE_STATE_TRANSIT_FORCE(
- PD_HW_MSG_TX_FAILED, PE_SNK_SEND_SOFT_RESET);
- break;
- };
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess PE MSG
- */
-
-static inline bool pd_process_pe_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_PE_RESET_PRL_COMPLETED:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_RESET_PRL_COMPLETED);
- break;
-
- case PD_PE_HARD_RESET_COMPLETED:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_HARD_RESET_COMPLETED);
- break;
-
- case PD_PE_POWER_ROLE_AT_DEFAULT:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_POWER_ROLE_AT_DEFAULT);
- break;
-
- case PD_PE_IDLE:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_IDLE);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-
-static inline void pd_report_typec_only_charger(pd_port_t *pd_port)
-{
- /* TODO: pd_set_rx_enable(pd_port, PD_RX_CAP_PE_DISABLE);*/
- PE_INFO("TYPE-C Only Charger!\r\n");
- pd_dpm_sink_vbus(pd_port, true);
- pd_update_connect_state(pd_port, PD_CONNECT_TYPEC_ONLY);
-}
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_TIMER_BIST_CONT_MODE:
- ret = PE_MAKE_STATE_TRANSIT(PD_TIMER_BIST_CONT_MODE);
- break;
-
- case PD_TIMER_SINK_REQUEST:
- ret = PE_MAKE_STATE_TRANSIT(PD_TIMER_SINK_REQUEST);
- break;
-
-#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
- case PD_TIMER_SENDER_RESPONSE:
- ret = PE_MAKE_STATE_TRANSIT(PD_TIMER_SENDER_RESPONSE);
- break;
-
- case PD_TIMER_SINK_WAIT_CAP:
- case PD_TIMER_PS_TRANSITION:
- if (pd_port->hard_reset_counter <= PD_HARD_RESET_COUNT) {
- PE_TRANSIT_STATE(pd_port, PE_SNK_HARD_RESET);
- return true;
- }
- break;
-
-#ifdef CONFIG_USB_PD_FAST_RESP_TYPEC_SRC
- case PD_TIMER_SRC_RECOVER:
- if (pd_port->pe_state_curr == PE_SNK_STARTUP) {
- pd_disable_timer(pd_port, PD_TIMER_NO_RESPONSE);
- pd_report_typec_only_charger(pd_port);
- }
- break;
-#endif /* CONFIG_USB_PD_FAST_RESP_TYPEC_SRC */
-
- case PD_TIMER_NO_RESPONSE:
- if (!pd_dpm_check_vbus_valid(pd_port)) {
- PE_DBG("NoResp&VBUS=0\r\n");
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- ret = true;
- } else if (pd_port->hard_reset_counter <= PD_HARD_RESET_COUNT) {
- PE_TRANSIT_STATE(pd_port, PE_SNK_HARD_RESET);
- ret = true;
- } else if (pd_port->pd_prev_connected) {
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- ret = true;
- } else {
- pd_report_typec_only_charger(pd_port);
- }
- break;
-#endif
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- case PD_TIMER_DISCOVER_ID:
- vdm_put_dpm_discover_cable_event(pd_port);
- break;
-#endif
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Process Policy Engine's SNK Message
- */
-
-bool pd_process_event_snk(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DATA_MSG:
- return pd_process_data_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_HW_MSG:
- return pd_process_hw_msg(pd_port, pd_event);
-
- case PD_EVT_PE_MSG:
- return pd_process_pe_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
-
- default:
- return false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For SRC
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-
-/* PD Control MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GOOD_CRC) = {
- { PE_SRC_TRANSITION_SUPPLY2, PE_SRC_READY },
- { PE_SRC_GIVE_SOURCE_CAP, PE_SRC_READY },
- { PE_SRC_SOFT_RESET, PE_SRC_SEND_CAPABILITIES },
-
- { PE_DR_SRC_GIVE_SINK_CAP, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GOOD_CRC);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_GET_SOURCE_CAP) = {
- { PE_SRC_READY, PE_SRC_GIVE_SOURCE_CAP },
-
-/* Handler Port Partner Request first */
- { PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_GIVE_SOURCE_CAP},
- { PE_SRC_GET_SINK_CAP, PE_SRC_GIVE_SOURCE_CAP},
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_GET_SOURCE_CAP);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_ACCEPT) = {
- {PE_SRC_SEND_SOFT_RESET, PE_SRC_SEND_CAPABILITIES },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_ACCEPT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_REJECT) = {
- { PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_REJECT);
-
-/* PD Data MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DATA_MSG_REQUEST) = {
- { PE_SRC_SEND_CAPABILITIES, PE_SRC_NEGOTIATE_CAPABILITIES },
- { PE_SRC_READY, PE_SRC_NEGOTIATE_CAPABILITIES },
-
-/* Handler Port Partner Request first */
- { PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_GIVE_SOURCE_CAP},
- { PE_SRC_GET_SINK_CAP, PE_SRC_GIVE_SOURCE_CAP},
-};
-
-DECL_PE_STATE_REACTION(PD_DATA_MSG_REQUEST);
-
-DECL_PE_STATE_TRANSITION(PD_DATA_MSG_SOURCE_CAP) = {
- { PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_DATA_MSG_SOURCE_CAP);
-
-DECL_PE_STATE_TRANSITION(PD_DATA_MSG_SINK_CAP) = {
- { PE_SRC_GET_SINK_CAP, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_DATA_MSG_SINK_CAP);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_SRC_NEGOTIATE_CAPABILITIES, PE_SRC_TRANSITION_SUPPLY },
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- { PE_SRC_STARTUP, PE_SRC_SEND_CAPABILITIES },
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
- { PE_SRC_NEGOTIATE_CAPABILITIES, PE_SRC_CAPABILITY_RESPONSE },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_CAP_CHANGED) = {
- { PE_SRC_READY, PE_SRC_SEND_CAPABILITIES },
- { PE_SRC_WAIT_NEW_CAPABILITIES, PE_SRC_SEND_CAPABILITIES },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_CAP_CHANGED);
-
-/* HW Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_HW_MSG_TX_FAILED) = {
- { PE_SRC_SOFT_RESET, PE_SRC_HARD_RESET },
- { PE_SRC_SEND_SOFT_RESET, PE_SRC_HARD_RESET },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_MSG_TX_FAILED);
-
-DECL_PE_STATE_TRANSITION(PD_HW_VBUS_STABLE) = {
- { PE_SRC_TRANSITION_SUPPLY, PE_SRC_TRANSITION_SUPPLY2 },
-};
-
-DECL_PE_STATE_REACTION(PD_HW_VBUS_STABLE);
-
-/* PE Event reactions */
-
-/* TODO: Remove it later, always trigger by pd_evt_source_start_timeout */
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_RESET_PRL_COMPLETED) = {
- { PE_SRC_STARTUP, PE_SRC_SEND_CAPABILITIES },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_RESET_PRL_COMPLETED);
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_POWER_ROLE_AT_DEFAULT) = {
- { PE_SRC_TRANSITION_TO_DEFAULT, PE_SRC_STARTUP },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_POWER_ROLE_AT_DEFAULT);
-
-DECL_PE_STATE_TRANSITION(PD_PE_MSG_IDLE) = {
- { PE_IDLE1, PE_IDLE2 },
-};
-
-DECL_PE_STATE_REACTION(PD_PE_MSG_IDLE);
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SENDER_RESPONSE) = {
- { PE_SRC_SEND_CAPABILITIES, PE_SRC_HARD_RESET },
- { PE_SRC_SEND_SOFT_RESET, PE_SRC_HARD_RESET },
-
- { PE_SRC_GET_SINK_CAP, PE_SRC_READY },
- { PE_DR_SRC_GET_SOURCE_CAP, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SENDER_RESPONSE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_PS_HARD_RESET) = {
- { PE_SRC_HARD_RESET, PE_SRC_TRANSITION_TO_DEFAULT },
- { PE_SRC_HARD_RESET_RECEIVED, PE_SRC_TRANSITION_TO_DEFAULT },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_PS_HARD_RESET);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_BIST_CONT_MODE) = {
- { PE_BIST_CARRIER_MODE_2, PE_SRC_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_BIST_CONT_MODE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SOURCE_START) = {
- { PE_SRC_STARTUP, PE_SRC_SEND_CAPABILITIES },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SOURCE_START);
-
-/*
- * [BLOCK] Porcess Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-
-{
- switch (pd_port->pe_state_curr) {
- case PE_SRC_SEND_SOFT_RESET:
- case PE_SRC_GET_SINK_CAP:
- case PE_DR_SRC_GET_SOURCE_CAP:
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- return false;
-
- case PE_SRC_SEND_CAPABILITIES:
- pd_disable_timer(pd_port, PD_TIMER_NO_RESPONSE);
- pd_port->cap_counter = 0;
- pd_port->hard_reset_counter = 0;
- pd_notify_pe_hard_reset_completed(pd_port);
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- /* pd_set_cc_res(pd_port, TYPEC_CC_RP_1_5); */
- return false;
-
- case PE_SRC_CAPABILITY_RESPONSE:
- if (!pd_port->explicit_contract)
- PE_TRANSIT_STATE(pd_port, PE_SRC_WAIT_NEW_CAPABILITIES);
- else if (pd_port->invalid_contract)
- PE_TRANSIT_STATE(pd_port, PE_SRC_HARD_RESET);
- else
- PE_TRANSIT_STATE(pd_port, PE_SRC_READY);
- return true;
- default:
- return PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GOOD_CRC);
- }
-}
-
-static inline bool pd_process_ctrl_msg_get_sink_cap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SRC_READY:
- case PE_DR_SRC_GET_SOURCE_CAP:
- case PE_SRC_GET_SINK_CAP:
- break;
-
- default:
- return false;
- }
-
- if (pd_port->dpm_caps & DPM_CAP_LOCAL_DR_POWER) {
- PE_TRANSIT_STATE(pd_port, PE_DR_SRC_GIVE_SINK_CAP);
- return true;
- }
- pd_send_ctrl_msg(pd_port, TCPC_TX_SOP, PD_CTRL_REJECT);
- return false;
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- case PD_CTRL_ACCEPT:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_ACCEPT);
- break;
-
- case PD_CTRL_REJECT:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_REJECT);
- break;
-
- case PD_CTRL_GET_SOURCE_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_GET_SOURCE_CAP);
- break;
-
- case PD_CTRL_GET_SINK_CAP:
- ret = pd_process_ctrl_msg_get_sink_cap(pd_port, pd_event);
- break;
-
- /* Swap */
- case PD_CTRL_DR_SWAP:
- ret = pd_process_ctrl_msg_dr_swap(pd_port, pd_event);
- break;
-
- case PD_CTRL_PR_SWAP:
- ret = pd_process_ctrl_msg_pr_swap(pd_port, pd_event);
- break;
-
- case PD_CTRL_VCONN_SWAP:
- ret = pd_process_ctrl_msg_vconn_swap(pd_port, pd_event);
- break;
-
- /* SoftReset */
- case PD_CTRL_SOFT_RESET:
- if (!pd_port->during_swap) {
- PE_TRANSIT_STATE(pd_port, PE_SRC_SOFT_RESET);
- return true;
- }
- break;
-
- /* Ignore */
- case PD_CTRL_PING:
- pd_notify_pe_recv_ping_event(pd_port);
- case PD_CTRL_PS_RDY:
- case PD_CTRL_GOTO_MIN:
- case PD_CTRL_WAIT:
- break;
- }
-
- if (!ret)
- ret = pd_process_protocol_error(pd_port, pd_event);
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Data MSG
- */
-
-static inline bool pd_process_data_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DATA_SOURCE_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_SOURCE_CAP);
- break;
-
- case PD_DATA_SINK_CAP:
- ret = PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_SINK_CAP);
- break;
-
- case PD_DATA_BIST:
- ret = pd_process_data_msg_bist(pd_port, pd_event);
- break;
-
- case PD_DATA_REQUEST:
- ret = PE_MAKE_STATE_TRANSIT(PD_DATA_MSG_REQUEST);
- break;
-
- case PD_DATA_VENDOR_DEF:
- return false;
- }
-
- if (!ret)
- ret = pd_process_protocol_error(pd_port, pd_event);
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess DPM MSG
- */
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
- break;
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
- case PD_DPM_CAP_CHANGED:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_CAP_CHANGED);
- break;
-
- case PD_DPM_ERROR_RECOVERY:
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- return true;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess HW MSG
- */
-
-static inline bool pd_process_hw_msg_vbus_present(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_SRC_STARTUP:
- pd_enable_timer(pd_port, PD_TIMER_SOURCE_START);
- break;
-
- case PE_SRC_TRANSITION_TO_DEFAULT:
- pd_put_pe_event(pd_port, PD_PE_POWER_ROLE_AT_DEFAULT);
- break;
- }
-
- return false;
-}
-
-static inline bool pd_process_hw_msg_tx_failed(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr == PE_SRC_SEND_CAPABILITIES) {
- if (pd_port->pd_connected) {
- PE_DBG("PR_SWAP NoResp\r\n");
- return false;
- }
-
- PE_TRANSIT_STATE(pd_port, PE_SRC_DISCOVERY);
- return true;
- }
-
- return PE_MAKE_STATE_TRANSIT_FORCE(
- PD_HW_MSG_TX_FAILED, PE_SRC_SEND_SOFT_RESET);
-}
-
-static inline bool pd_process_hw_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_HW_CC_DETACHED:
- PE_TRANSIT_STATE(pd_port, PE_IDLE1);
- return true;
-
- case PD_HW_CC_ATTACHED:
- PE_TRANSIT_STATE(pd_port, PE_SRC_STARTUP);
- return true;
-
- case PD_HW_RECV_HARD_RESET:
- ret = pd_process_recv_hard_reset(
- pd_port, pd_event, PE_SRC_HARD_RESET_RECEIVED);
- break;
-
- case PD_HW_VBUS_PRESENT:
- ret = pd_process_hw_msg_vbus_present(pd_port, pd_event);
- break;
-
- case PD_HW_VBUS_SAFE0V:
- pd_enable_timer(pd_port, PD_TIMER_SRC_RECOVER);
- break;
-
- case PD_HW_VBUS_STABLE:
- ret = PE_MAKE_STATE_TRANSIT(PD_HW_VBUS_STABLE);
- break;
-
- case PD_HW_TX_FAILED:
- ret = pd_process_hw_msg_tx_failed(pd_port, pd_event);
- break;
-
- case PD_HW_VBUS_ABSENT:
- break;
- };
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess PE MSG
- */
-
-static inline bool pd_process_pe_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_PE_RESET_PRL_COMPLETED:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_RESET_PRL_COMPLETED);
- break;
-
- case PD_PE_POWER_ROLE_AT_DEFAULT:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_POWER_ROLE_AT_DEFAULT);
- break;
-
- case PD_PE_IDLE:
- ret = PE_MAKE_STATE_TRANSIT(PD_PE_MSG_IDLE);
- break;
- }
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-static inline bool pd_process_timer_msg_source_start(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- if (pd_is_auto_discover_cable_id(pd_port)) {
- if (vdm_put_dpm_discover_cable_event(pd_port)) {
- /* waiting for dpm_ack event */
- return false;
- }
- }
-#endif
-
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_SOURCE_START);
-}
-
-static inline bool pd_process_timer_msg_source_cap(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr != PE_SRC_DISCOVERY)
- return false;
-
- if (pd_port->cap_counter <= PD_CAPS_COUNT)
- PE_TRANSIT_STATE(pd_port, PE_SRC_SEND_CAPABILITIES);
- else /* in this state, PD always not connected */
- PE_TRANSIT_STATE(pd_port, PE_SRC_DISABLED);
-
- return true;
-}
-
-static inline bool pd_process_timer_msg_no_response(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->hard_reset_counter <= PD_HARD_RESET_COUNT)
- PE_TRANSIT_STATE(pd_port, PE_SRC_HARD_RESET);
- else if (pd_port->pd_prev_connected)
- PE_TRANSIT_STATE(pd_port, PE_ERROR_RECOVERY);
- else
- PE_TRANSIT_STATE(pd_port, PE_SRC_DISABLED);
-
- return true;
-}
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_TIMER_BIST_CONT_MODE:
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_BIST_CONT_MODE);
-
- case PD_TIMER_SOURCE_CAPABILITY:
- return pd_process_timer_msg_source_cap(pd_port, pd_event);
-
-#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
- case PD_TIMER_SENDER_RESPONSE:
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_SENDER_RESPONSE);
-#endif
-
- case PD_TIMER_PS_HARD_RESET:
- return PE_MAKE_STATE_TRANSIT(PD_TIMER_PS_HARD_RESET);
-
- case PD_TIMER_SOURCE_START:
- return pd_process_timer_msg_source_start(pd_port, pd_event);
-
-#ifndef CONFIG_USB_PD_DBG_IGRONE_TIMEOUT
- case PD_TIMER_NO_RESPONSE:
- return pd_process_timer_msg_no_response(pd_port, pd_event);
-#endif
-
- case PD_TIMER_SOURCE_TRANSITION:
- if (pd_port->state_machine != PE_STATE_MACHINE_PR_SWAP)
- pd_dpm_src_transition_power(pd_port, pd_event);
- break;
-
-#ifdef CONFIG_PD_DISCOVER_CABLE_ID
- case PD_TIMER_DISCOVER_ID:
- vdm_put_dpm_discover_cable_event(pd_port);
- break;
-#endif
-
- case PD_TIMER_SRC_RECOVER:
- pd_dpm_source_vbus(pd_port, true);
- pd_enable_vbus_valid_detection(pd_port, true);
- break;
- }
-
- return false;
-}
-
-/*
- * [BLOCK] Process Policy Engine's SRC Message
- */
-
-bool pd_process_event_src(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DATA_MSG:
- return pd_process_data_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_HW_MSG:
- return pd_process_hw_msg(pd_port, pd_event);
-
- case PD_EVT_PE_MSG:
- return pd_process_pe_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
-
- default:
- return false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For VCS
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-
-/* PD Control MSG reactions */
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_REJECT_WAIT) = {
- { PE_VCS_SEND_SWAP, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_REJECT_WAIT);
-
-DECL_PE_STATE_TRANSITION(PD_CTRL_MSG_PS_RDY) = {
- { PE_VCS_WAIT_FOR_VCONN, PE_VCS_TURN_OFF_VCONN },
-};
-
-DECL_PE_STATE_REACTION(PD_CTRL_MSG_PS_RDY);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_VCS_EVALUATE_SWAP, PE_VCS_ACCEPT_SWAP },
- { PE_VCS_TURN_ON_VCONN, PE_VCS_SEND_PS_RDY },
- { PE_VCS_TURN_OFF_VCONN, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
- { PE_VCS_EVALUATE_SWAP, PE_VCS_REJECT_VCONN_SWAP },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_SENDER_RESPONSE) = {
- { PE_VCS_SEND_SWAP, PE_VIRT_READY },
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_SENDER_RESPONSE);
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_VCONN_ON) = {
- { PE_VCS_WAIT_FOR_VCONN, PE_VIRT_HARD_RESET},
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_VCONN_ON);
-
-/*
- * [BLOCK] Porcess PD Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_VCS_REJECT_VCONN_SWAP:
- case PE_VCS_SEND_PS_RDY:
- PE_TRANSIT_READY_STATE(pd_port);
- return true;
-
- case PE_VCS_ACCEPT_SWAP:
- PE_TRANSIT_VCS_SWAP_STATE(pd_port);
- return true;
-
- case PE_VCS_SEND_SWAP:
- pd_enable_timer(pd_port, PD_TIMER_SENDER_RESPONSE);
- return false;
-
- default:
- return false;
- }
-}
-
-static inline bool pd_process_ctrl_msg_accept(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->pe_state_curr == PE_VCS_SEND_SWAP) {
- PE_TRANSIT_VCS_SWAP_STATE(pd_port);
- return true;
- }
-
- return false;
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- case PD_CTRL_ACCEPT:
- return pd_process_ctrl_msg_accept(pd_port, pd_event);
-
- case PD_CTRL_WAIT:
- case PD_CTRL_REJECT:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_CTRL_MSG_REJECT_WAIT);
- break;
-
- case PD_CTRL_PS_RDY:
- ret = PE_MAKE_STATE_TRANSIT(PD_CTRL_MSG_PS_RDY);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess DPM MSG
- */
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_DPM_MSG_ACK);
- break;
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_TIMER_SENDER_RESPONSE:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_TIMER_SENDER_RESPONSE);
- break;
-
- case PD_TIMER_VCONN_ON:
- ret = PE_MAKE_STATE_TRANSIT_VIRT(PD_TIMER_VCONN_ON);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Process Policy Engine's VCS Message
- */
-
-bool pd_process_event_vcs(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
-
- default:
- return false;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Process Event For VDM
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/pd_process_evt.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-
-#define VDM_CMD_STATE(cmd, cmd_type) \
- (((cmd) & 0x1f) | (((cmd_type) & 0x03) << 6))
-
-#define VDM_CMD_INIT_STATE(cmd, next_state) \
- { VDM_CMD_STATE(cmd, CMDT_INIT), next_state }
-
-#define VDM_CMD_ACK_STATE(cmd, next_state) \
- { VDM_CMD_STATE(cmd, CMDT_RSP_ACK), next_state }
-
-#define VDM_CMD_NACK_STATE(cmd, next_state) \
- { VDM_CMD_STATE(cmd, CMDT_RSP_NAK), next_state }
-
-#define VDM_CMD_BUSY_STATE(cmd, next_state) \
- { VDM_CMD_STATE(cmd, CMDT_RSP_BUSY), next_state }
-
-/* UFP PD VDM Command's reactions */
-
-DECL_PE_STATE_TRANSITION(PD_UFP_VDM_CMD) = {
- VDM_CMD_INIT_STATE(CMD_DISCOVER_IDENT, PE_UFP_VDM_GET_IDENTITY),
- VDM_CMD_INIT_STATE(CMD_DISCOVER_SVID, PE_UFP_VDM_GET_SVIDS),
- VDM_CMD_INIT_STATE(CMD_DISCOVER_MODES, PE_UFP_VDM_GET_MODES),
- VDM_CMD_INIT_STATE(CMD_ENTER_MODE, PE_UFP_VDM_EVALUATE_MODE_ENTRY),
- VDM_CMD_INIT_STATE(CMD_EXIT_MODE, PE_UFP_VDM_MODE_EXIT),
- /* CHECK IT LATER */
- VDM_CMD_INIT_STATE(CMD_ATTENTION, PE_UFP_VDM_ATTENTION_REQUEST),
-};
-
-DECL_PE_STATE_REACTION(PD_UFP_VDM_CMD);
-
-/* DFP PD VDM Command's reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_DISCOVER_ID) = {
- VDM_CMD_ACK_STATE(CMD_DISCOVER_IDENT,
- PE_DFP_UFP_VDM_IDENTITY_ACKED),
- VDM_CMD_NACK_STATE(CMD_DISCOVER_IDENT, PE_DFP_UFP_VDM_IDENTITY_NAKED),
- VDM_CMD_BUSY_STATE(CMD_DISCOVER_IDENT, PE_DFP_UFP_VDM_IDENTITY_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_DISCOVER_ID);
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_DISCOVER_SVID) = {
- VDM_CMD_ACK_STATE(CMD_DISCOVER_SVID,
- PE_DFP_VDM_SVIDS_ACKED),
- VDM_CMD_NACK_STATE(CMD_DISCOVER_SVID, PE_DFP_VDM_SVIDS_NAKED),
- VDM_CMD_BUSY_STATE(CMD_DISCOVER_SVID, PE_DFP_VDM_SVIDS_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_DISCOVER_SVID);
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_DISCOVER_MODES) = {
- VDM_CMD_ACK_STATE(CMD_DISCOVER_MODES,
- PE_DFP_VDM_MODES_ACKED),
- VDM_CMD_NACK_STATE(CMD_DISCOVER_MODES, PE_DFP_VDM_MODES_NAKED),
- VDM_CMD_BUSY_STATE(CMD_DISCOVER_MODES, PE_DFP_VDM_MODES_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_DISCOVER_MODES);
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_ENTER_MODE) = {
- VDM_CMD_ACK_STATE(CMD_ENTER_MODE,
- PE_DFP_VDM_MODE_ENTRY_ACKED),
- VDM_CMD_NACK_STATE(CMD_ENTER_MODE, PE_DFP_VDM_MODE_ENTRY_NAKED),
- VDM_CMD_BUSY_STATE(CMD_ENTER_MODE, PE_DFP_VDM_MODE_ENTRY_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_ENTER_MODE);
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_EXIT_MODE) = {
- VDM_CMD_ACK_STATE(CMD_EXIT_MODE,
- PE_DFP_VDM_MODE_ENTRY_ACKED),
- VDM_CMD_NACK_STATE(CMD_EXIT_MODE,
- PE_DFP_VDM_MODE_ENTRY_NAKED),
- VDM_CMD_BUSY_STATE(CMD_EXIT_MODE,
- PE_VIRT_HARD_RESET),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_EXIT_MODE);
-
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_ATTENTION) = {
- VDM_CMD_INIT_STATE(CMD_ATTENTION,
- PE_DFP_VDM_ATTENTION_REQUEST),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_ATTENTION);
-/* HW Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_HW_MSG_TX_FAILED) = {
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- {PE_SRC_VDM_IDENTITY_REQUEST, PE_SRC_VDM_IDENTITY_NAKED},
-#endif /* PD_CAP_SRC_STARTUP_DISCOVERY_ID */
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- {PE_DFP_CBL_VDM_IDENTITY_REQUEST, PE_DFP_CBL_VDM_IDENTITY_NAKED},
-#endif
-};
-
-DECL_PE_STATE_REACTION(PD_HW_MSG_TX_FAILED);
-
-/* DPM Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_ACK) = {
- { PE_UFP_VDM_GET_IDENTITY, PE_UFP_VDM_SEND_IDENTITY },
- { PE_UFP_VDM_GET_SVIDS, PE_UFP_VDM_SEND_SVIDS },
- { PE_UFP_VDM_GET_MODES, PE_UFP_VDM_SEND_MODES },
- { PE_UFP_VDM_MODE_EXIT, PE_UFP_VDM_MODE_EXIT_ACK},
- { PE_UFP_VDM_EVALUATE_MODE_ENTRY, PE_UFP_VDM_MODE_ENTRY_ACK },
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_ACK);
-
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_NAK) = {
- {PE_UFP_VDM_GET_IDENTITY, PE_UFP_VDM_GET_IDENTITY_NAK},
- {PE_UFP_VDM_GET_SVIDS, PE_UFP_VDM_GET_SVIDS_NAK},
- {PE_UFP_VDM_GET_MODES, PE_UFP_VDM_GET_MODES_NAK},
- {PE_UFP_VDM_MODE_EXIT, PE_UFP_VDM_MODE_EXIT_NAK},
- {PE_UFP_VDM_EVALUATE_MODE_ENTRY, PE_UFP_VDM_MODE_ENTRY_NAK},
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_NAK);
-
-/* Discover Cable ID */
-
-#ifdef CONFIG_PD_DISCOVER_CABLE_ID
-DECL_PE_STATE_TRANSITION(PD_DPM_MSG_DISCOVER_CABLE) = {
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- { PE_SRC_STARTUP, PE_SRC_VDM_IDENTITY_REQUEST},
- { PE_SRC_DISCOVERY, PE_SRC_VDM_IDENTITY_REQUEST},
-#endif
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- { PE_SRC_READY, PE_DFP_CBL_VDM_IDENTITY_REQUEST},
- { PE_SNK_READY, PE_DFP_CBL_VDM_IDENTITY_REQUEST},
-#endif
-};
-
-DECL_PE_STATE_REACTION(PD_DPM_MSG_DISCOVER_CABLE);
-#endif
-
-/* Source Startup Discover Cable ID */
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
-DECL_PE_STATE_TRANSITION(PD_SRC_VDM_DISCOVER_CABLE) = {
- VDM_CMD_ACK_STATE(CMD_DISCOVER_IDENT, PE_SRC_VDM_IDENTITY_ACKED),
- VDM_CMD_NACK_STATE(CMD_DISCOVER_IDENT, PE_SRC_VDM_IDENTITY_NAKED),
- VDM_CMD_BUSY_STATE(CMD_DISCOVER_IDENT, PE_SRC_VDM_IDENTITY_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_SRC_VDM_DISCOVER_CABLE);
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
-DECL_PE_STATE_TRANSITION(PD_DFP_VDM_DISCOVER_CABLE) = {
- VDM_CMD_ACK_STATE(CMD_DISCOVER_IDENT, PE_DFP_CBL_VDM_IDENTITY_ACKED),
- VDM_CMD_NACK_STATE(CMD_DISCOVER_IDENT, PE_DFP_CBL_VDM_IDENTITY_NAKED),
- VDM_CMD_BUSY_STATE(CMD_DISCOVER_IDENT, PE_DFP_CBL_VDM_IDENTITY_NAKED),
-};
-
-DECL_PE_STATE_REACTION(PD_DFP_VDM_DISCOVER_CABLE);
-
-#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
-
-/* Timer Event reactions */
-
-DECL_PE_STATE_TRANSITION(PD_TIMER_VDM_RESPONSE) = {
- { PE_DFP_UFP_VDM_IDENTITY_REQUEST, PE_DFP_UFP_VDM_IDENTITY_NAKED },
- { PE_DFP_VDM_SVIDS_REQUEST, PE_DFP_VDM_SVIDS_NAKED },
- { PE_DFP_VDM_MODES_REQUEST, PE_DFP_VDM_MODES_NAKED },
- { PE_DFP_VDM_MODE_EXIT_REQUEST, PE_VIRT_HARD_RESET },
- { PE_DFP_VDM_MODE_ENTRY_REQUEST, PE_DFP_VDM_MODE_ENTRY_NAKED },
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- { PE_SRC_VDM_IDENTITY_REQUEST, PE_SRC_VDM_IDENTITY_NAKED },
-#endif
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- { PE_DFP_CBL_VDM_IDENTITY_REQUEST, PE_DFP_CBL_VDM_IDENTITY_NAKED },
-#endif
-};
-
-DECL_PE_STATE_REACTION(PD_TIMER_VDM_RESPONSE);
-
-/*
- * [BLOCK] Porcess Ctrl MSG
- */
-
-static inline bool pd_process_ctrl_msg_good_crc(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
- case PE_UFP_VDM_SEND_IDENTITY:
- case PE_UFP_VDM_GET_IDENTITY_NAK:
- case PE_UFP_VDM_SEND_SVIDS:
- case PE_UFP_VDM_GET_SVIDS_NAK:
-
- case PE_UFP_VDM_SEND_MODES:
- case PE_UFP_VDM_GET_MODES_NAK:
- case PE_UFP_VDM_MODE_ENTRY_ACK:
- case PE_UFP_VDM_MODE_ENTRY_NAK:
- case PE_UFP_VDM_MODE_EXIT_ACK:
- case PE_UFP_VDM_MODE_EXIT_NAK:
-
- PE_TRANSIT_READY_STATE(pd_port);
- return true;
-
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- case PE_SRC_VDM_IDENTITY_REQUEST:
- pd_port->power_cable_present = true;
- return false;
-#endif
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- case PE_DFP_CBL_VDM_IDENTITY_REQUEST:
- pd_port->power_cable_present = true;
- return false;
-#endif
- }
-
- return false;
-}
-
-static inline bool pd_process_ctrl_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_CTRL_GOOD_CRC:
- return pd_process_ctrl_msg_good_crc(pd_port, pd_event);
-
- default:
- break;
- }
-
- return ret;
-}
-
-static inline bool pd_process_uvdm(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- return false;
-}
-
-/*
- * [BLOCK] Porcess Data MSG (VDM)
- */
-
-#if (PE_EVT_INFO_VDM_DIS == 0)
-static const char * const pe_vdm_cmd_name[] = {
- "DiscoverID",
- "DiscoverSVID",
- "DiscoverMode",
- "EnterMode",
- "ExitMode",
- "Attention",
-};
-
-static const char *const pe_vdm_dp_cmd_name[] = {
- "DPStatus",
- "DPConfig",
-};
-
-static const char * const pe_vdm_cmd_type_name[] = {
- "INIT",
- "ACK",
- "NACK",
- "BUSY",
-};
-#endif /* if (PE_EVT_INFO_VDM_DIS == 0) */
-
-static inline void print_vdm_msg(pd_port_t *pd_port, pd_event_t *pd_event)
-{
-#if (PE_EVT_INFO_VDM_DIS == 0)
- u8 cmd;
- u8 cmd_type;
- const char *name = NULL;
- u32 vdm_hdr = pd_event->pd_msg->payload[0];
-
- cmd = PD_VDO_CMD(vdm_hdr);
- cmd_type = PD_VDO_CMDT(vdm_hdr);
-
- if (cmd <= ARRAY_SIZE(pe_vdm_cmd_name))
- name = pe_vdm_cmd_name[cmd - 1];
- if (!name)
- return;
-
- if (cmd_type >= ARRAY_SIZE(pe_vdm_cmd_type_name))
- return;
-
- PE_DBG("%s:%s\r\n", name, pe_vdm_cmd_type_name[cmd_type]);
-
-#endif /* PE_EVT_INFO_VDM_DIS */
-}
-
-static inline bool pd_process_ufp_vdm(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (!pd_check_pe_state_ready(pd_port)) {
- PE_DBG("659 : invalid, current status\r\n");
- return false;
- }
-
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_UFP_VDM_CMD))
- return true;
-
- return false;
-}
-
-static inline bool pd_process_dfp_vdm(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- u32 vdm_hdr = pd_event->pd_msg->payload[0];
-
- if ((PD_VDO_CMDT(vdm_hdr) == CMDT_INIT) &&
- PD_VDO_CMD(vdm_hdr) == CMD_ATTENTION) {
- if (!pd_check_pe_state_ready(pd_port)) {
- PE_DBG("670 : invalid, current status\r\n");
- return false;
- }
-
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_ATTENTION))
- return true;
- }
-
- switch (pd_port->pe_state_curr) {
- case PE_DFP_UFP_VDM_IDENTITY_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_DISCOVER_ID))
- return true;
-
- case PE_DFP_VDM_SVIDS_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_DISCOVER_SVID))
- return true;
-
- case PE_DFP_VDM_MODES_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_DISCOVER_MODES))
- return true;
-
- case PE_DFP_VDM_MODE_ENTRY_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_ENTER_MODE))
- return true;
-
- case PE_DFP_VDM_MODE_EXIT_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT_VIRT(PD_DFP_VDM_EXIT_MODE))
- return true;
- }
- return false;
-}
-
-static inline bool pd_process_sop_vdm(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- if (pd_port->data_role == PD_ROLE_UFP)
- ret = pd_process_ufp_vdm(pd_port, pd_event);
- else
- ret = pd_process_dfp_vdm(pd_port, pd_event);
-
- if (!ret)
- PE_DBG("Unknown VDM\r\n");
- return ret;
-}
-
-static inline bool pd_process_sop_prime_vdm(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_port->pe_state_curr) {
-#ifdef CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID
- case PE_SRC_VDM_IDENTITY_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_SRC_VDM_DISCOVER_CABLE))
- return true;
-#endif /* CONFIG_USB_PD_SRC_STARTUP_DISCOVER_ID */
-
-#ifdef CONFIG_USB_PD_DFP_READY_DISCOVER_ID
- case PE_DFP_CBL_VDM_IDENTITY_REQUEST:
- if (PE_MAKE_VDM_CMD_STATE_TRANSIT(PD_DFP_VDM_DISCOVER_CABLE))
- return true;
-#endif /* CONFIG_USB_PD_DFP_READY_DISCOVER_ID */
- }
- return false;
-}
-
-static inline bool pd_process_data_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
- u32 vdm_hdr;
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- if (pd_event->msg != PD_DATA_VENDOR_DEF)
- return ret;
-
- vdm_hdr = pd_msg->payload[0];
- if (!PD_VDO_SVDM(vdm_hdr))
- return pd_process_uvdm(pd_port, pd_event);
-
- /* From Port Partner, copy curr_state from pd_state */
- if (PD_VDO_CMDT(vdm_hdr) == CMDT_INIT) {
- pd_port->pe_vdm_state = pd_port->pe_pd_state;
- pd_port->pe_state_curr = pd_port->pe_pd_state;
-#if PE_DBG_RESET_VDM_DIS == 0
- PE_DBG("reset vdm_state\r\n");
-#endif /* if PE_DBG_RESET_VDM_DIS == 0 */
- }
-
- print_vdm_msg(pd_port, pd_event);
-
- if (pd_msg->frame_type == TCPC_TX_SOP_PRIME)
- ret = pd_process_sop_prime_vdm(pd_port, pd_event);
- else
- ret = pd_process_sop_vdm(pd_port, pd_event);
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess PDM MSG
- */
-
-static inline bool pd_process_dpm_msg_ack(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- if (pd_port->data_role == PD_ROLE_DFP) {
- switch (pd_port->pe_state_curr) {
- case PE_DFP_UFP_VDM_IDENTITY_ACKED:
- case PE_DFP_UFP_VDM_IDENTITY_NAKED:
- case PE_DFP_CBL_VDM_IDENTITY_ACKED:
- case PE_DFP_CBL_VDM_IDENTITY_NAKED:
- case PE_DFP_VDM_SVIDS_ACKED:
- case PE_DFP_VDM_SVIDS_NAKED:
- case PE_DFP_VDM_MODES_ACKED:
- case PE_DFP_VDM_MODES_NAKED:
- case PE_DFP_VDM_MODE_ENTRY_ACKED:
- case PE_DFP_VDM_MODE_EXIT_REQUEST:
- case PE_DFP_VDM_MODE_EXIT_ACKED:
- case PE_DFP_VDM_ATTENTION_REQUEST:
- PE_TRANSIT_READY_STATE(pd_port);
- return true;
- default:
- return false;
- }
- } else {
- return PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_ACK);
- }
-}
-
-static inline bool pd_process_dpm_msg_vdm_request(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool is_dfp;
- bool is_attention;
-
- if (!pd_check_pe_state_ready(pd_port)) {
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_NOT_READY);
- PE_DBG("skip vdm_request, not ready_state (%d)\r\n",
- pd_port->pe_state_curr);
- return false;
- }
-
- is_dfp = pd_port->data_role == PD_ROLE_DFP;
- is_attention = pd_event->msg_sec == PD_DPM_VDM_REQUEST_ATTENTION;
-
- if ((is_dfp && is_attention) || (!is_dfp && !is_attention)) {
- pd_update_dpm_request_state(pd_port, DPM_REQ_ERR_WRONG_ROLE);
- PE_DBG("skip vdm_request, not dfp\r\n");
- return false;
- }
-
- PE_TRANSIT_STATE(pd_port, pd_event->msg_sec);
- return true;
-}
-
-static inline bool pd_process_dpm_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_DPM_ACK:
- ret = pd_process_dpm_msg_ack(pd_port, pd_event);
- break;
-
- case PD_DPM_NAK:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_NAK);
- break;
-
- case PD_DPM_VDM_REQUEST:
- ret = pd_process_dpm_msg_vdm_request(pd_port, pd_event);
- break;
-
-#ifdef CONFIG_PD_DISCOVER_CABLE_ID
- case PD_DPM_DISCOVER_CABLE_ID:
- ret = PE_MAKE_STATE_TRANSIT(PD_DPM_MSG_DISCOVER_CABLE);
- break;
-#endif
- }
- return ret;
-}
-
-/*
- * [BLOCK] Porcess HW MSG
- */
-
-static inline bool pd_process_hw_msg_retry_vdm(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- PE_DBG("RetryVDM\r\n");
- return pd_process_sop_vdm(pd_port, pd_event);
-}
-
-static inline bool pd_process_hw_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- bool ret = false;
-
- switch (pd_event->msg) {
- case PD_HW_TX_FAILED:
- ret = PE_MAKE_STATE_TRANSIT(PD_HW_MSG_TX_FAILED);
- break;
-
- case PD_HW_RETRY_VDM:
- ret = pd_process_hw_msg_retry_vdm(pd_port, pd_event);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Porcess Timer MSG
- */
-
-static inline bool pd_process_timer_msg(
- pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->msg) {
- case PD_TIMER_VDM_RESPONSE:
- return PE_MAKE_STATE_TRANSIT_VIRT(PD_TIMER_VDM_RESPONSE);
-
- default:
- return false;
- }
-}
-
-/*
- * [BLOCK] Process Policy Engine's VDM Message
- */
-
-bool pd_process_event_vdm(pd_port_t *pd_port, pd_event_t *pd_event)
-{
- switch (pd_event->event_type) {
- case PD_EVT_CTRL_MSG:
- return pd_process_ctrl_msg(pd_port, pd_event);
-
- case PD_EVT_DATA_MSG:
- return pd_process_data_msg(pd_port, pd_event);
-
- case PD_EVT_DPM_MSG:
- return pd_process_dpm_msg(pd_port, pd_event);
-
- case PD_EVT_HW_MSG:
- return pd_process_hw_msg(pd_port, pd_event);
-
- case PD_EVT_TIMER_MSG:
- return pd_process_timer_msg(pd_port, pd_event);
- }
-
- return false;
-}
+++ /dev/null
-/* drivers/misc/rt-regmap.c
- * Richtek regmap with debugfs Driver
- *
- * Copyright (C) 2014 Richtek Technology Corp.
- * Author: Jeff Chang <jeff_chang@richtek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/sysfs.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/seq_file.h>
-#include <linux/semaphore.h>
-
-#include <linux/hisi/usb/pd/richtek/rt-regmap.h>
-
-struct rt_regmap_ops {
- int (*regmap_block_write)(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *data);
- int (*regmap_block_read)(struct rt_regmap_device *rd, u32 reg,
- int bytes, void *dest);
-};
-
-enum {
- RT_DBG_REG,
- RT_DBG_DATA,
- RT_DBG_REGS,
- RT_DBG_SYNC,
- RT_DBG_ERROR,
- RT_DBG_NAME,
- RT_DBG_BLOCK,
- RT_DBG_SIZE,
- RT_DBG_SLAVE_ADDR,
- RT_SUPPORT_MODE,
- RT_DBG_IO_LOG,
- RT_DBG_CACHE_MODE,
- RT_DBG_REG_SIZE,
-};
-
-struct reg_index_offset {
- int index;
- int offset;
-};
-
-struct rt_debug_data {
- struct reg_index_offset rio;
- unsigned int reg_addr;
- unsigned int reg_size;
- unsigned char part_id;
-};
-
-/* rt_regmap_device
- *
- * Richtek regmap device. One for each rt_regmap.
- *
- */
-struct rt_regmap_device {
- struct rt_regmap_properties props;
- struct rt_regmap_fops *rops;
- struct rt_regmap_ops regmap_ops;
- struct device dev;
- void *client;
- struct semaphore semaphore;
- struct dentry *rt_den;
- struct dentry *rt_debug_file[13];
- struct rt_debug_st rtdbg_st[13];
- struct dentry **rt_reg_file;
- struct rt_debug_st **reg_st;
- struct rt_debug_data dbg_data;
- struct delayed_work rt_work;
- unsigned char *cache_flag;
- unsigned char part_size_limit;
- unsigned char *alloc_data;
- char *err_msg;
-
- int (*rt_block_write[4])(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count);
- unsigned char cache_inited:1;
- unsigned char error_occurred:1;
- unsigned char pending_event:1;
-};
-
-struct dentry *rt_regmap_dir;
-
-static int get_parameters(char *buf, long int *param1, int num_of_par)
-{
- char *token;
- int base, cnt;
-
- token = strsep(&buf, " ");
-
- for (cnt = 0; cnt < num_of_par; cnt++) {
- if (token) {
- if ((token[1] == 'x') || (token[1] == 'X'))
- base = 16;
- else
- base = 10;
-
- if (kstrtoul(token, base, ¶m1[cnt]) != 0)
- return -EINVAL;
-
- token = strsep(&buf, " ");
- } else {
- return -EINVAL;
- }
- }
- return 0;
-}
-
-static int get_datas(const char *buf, const int length,
- unsigned char *data_buffer, unsigned char data_length)
-{
- int i, ptr;
- long int value;
- char token[5];
-
- token[0] = '0';
- token[1] = 'x';
- token[4] = 0;
- if (buf[0] != '0' || buf[1] != 'x')
- return -EINVAL;
-
- ptr = 2;
- for (i = 0; (i < data_length) && (ptr + 2 <= length); i++) {
- token[2] = buf[ptr++];
- token[3] = buf[ptr++];
- ptr++;
- if (kstrtoul(token, 16, &value) != 0)
- return -EINVAL;
- data_buffer[i] = value;
- }
- return 0;
-}
-
-static struct reg_index_offset find_register_index(
- const struct rt_regmap_device *rd, u32 reg)
-{
- const rt_register_map_t *rm = rd->props.rm;
- int register_num = rd->props.register_num;
- struct reg_index_offset rio = {0, 0};
- int index = 0, i = 0, unit = RT_1BYTE_MODE;
-
- for (index = 0; index < register_num; index++) {
- if (reg == rm[index]->addr) {
- rio.index = index;
- rio.offset = 0;
- break;
- } else if (reg > rm[index]->addr) {
- if ((reg - rm[index]->addr) < rm[index]->size) {
- rio.index = index;
- while (&rd->props.group[i]) {
- if (reg >= rd->props.group[i].start &&
- reg <= rd->props.group[i].end) {
- unit =
- rd->props.group[i].mode;
- break;
- }
- i++;
- unit = RT_1BYTE_MODE;
- }
- rio.offset =
- (reg - rm[index]->addr) * unit;
- } else {
- rio.index = -1;
- rio.offset = rio.index;
- }
- }
- }
- return rio;
-}
-
-static int rt_chip_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *src);
-
-/* rt_regmap_cache_sync - sync all cache data to real chip*/
-void rt_regmap_cache_sync(struct rt_regmap_device *rd)
-{
- int i, rc, num;
- const rt_register_map_t *rm = rd->props.rm;
-
- down(&rd->semaphore);
- if (!rd->pending_event)
- goto err_cache_sync;
-
- num = rd->props.register_num;
- for (i = 0; i < num; i++) {
- if (*(rd->cache_flag + i) == 1) {
- rc = rt_chip_block_write(rd, rm[i]->addr,
- rm[i]->size,
- rm[i]->cache_data);
- if (rc < 0) {
- dev_err(&rd->dev, "rt-regmap sync error\n");
- goto err_cache_sync;
- }
- *(rd->cache_flag + i) = 0;
- }
- }
- rd->pending_event = 0;
- dev_info(&rd->dev, "regmap sync successfully\n");
-err_cache_sync:
- up(&rd->semaphore);
-}
-EXPORT_SYMBOL(rt_regmap_cache_sync);
-
-/* rt_regmap_cache_write_back - write current cache data to chip
- * @rd: rt_regmap_device pointer.
- * @reg: register map address
- */
-void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg)
-{
- struct reg_index_offset rio;
- const rt_register_map_t *rm = rd->props.rm;
- int rc;
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of range\n", reg);
- return;
- }
-
- down(&rd->semaphore);
- if ((rm[rio.index]->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE) {
- rc = rt_chip_block_write(rd, rm[rio.index]->addr,
- rm[rio.index]->size,
- rm[rio.index]->cache_data);
- if (rc < 0) {
- dev_err(&rd->dev, "rt-regmap sync error\n");
- goto err_cache_chip_write;
- }
- *(rd->cache_flag + rio.index) = 0;
- }
- dev_info(&rd->dev, "regmap sync successfully\n");
-err_cache_chip_write:
- up(&rd->semaphore);
-}
-EXPORT_SYMBOL(rt_regmap_cache_write_back);
-
-/* rt_is_reg_volatile - check register map is volatile or not
- * @rd: rt_regmap_device pointer.
- * reg: register map address.
- */
-int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg)
-{
- struct reg_index_offset rio;
- rt_register_map_t rm;
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of range\n", reg);
- return -EINVAL;
- }
- rm = rd->props.rm[rio.index];
-
- return (rm->reg_type & RT_REG_TYPE_MASK) == RT_VOLATILE ? 1 : 0;
-}
-EXPORT_SYMBOL(rt_is_reg_volatile);
-
-/* rt_reg_regsize - get register map size for specific register
- * @rd: rt_regmap_device pointer.
- * reg: register map address
- */
-int rt_get_regsize(struct rt_regmap_device *rd, u32 reg)
-{
- struct reg_index_offset rio;
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0 || rio.offset != 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of map\n", reg);
- return -EINVAL;
- }
- return rd->props.rm[rio.index]->size;
-}
-EXPORT_SYMBOL(rt_get_regsize);
-
-static void rt_work_func(struct work_struct *work)
-{
- struct rt_regmap_device *rd;
-
- pr_info(" %s\n", __func__);
- rd = container_of(work, struct rt_regmap_device, rt_work.work);
- rt_regmap_cache_sync(rd);
-}
-
-static int rt_chip_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *src)
-{
- int ret;
-
- if ((rd->props.rt_regmap_mode & RT_IO_BLK_MODE_MASK) == RT_IO_BLK_ALL ||
- (rd->props.rt_regmap_mode & RT_IO_BLK_MODE_MASK) == RT_IO_BLK_CHIP)
- return 0;
-
- ret = rd->rops->write_device(rd->client, reg, bytes, src);
-
- return ret;
-}
-
-static int rt_chip_block_read(struct rt_regmap_device *rd, u32 reg,
- int bytes, void *dst)
-{
- int ret;
-
- ret = rd->rops->read_device(rd->client, reg, bytes, dst);
- return ret;
-}
-
-static int rt_cache_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *data)
-{
- int i, j, reg_base = 0, count = 0, ret = 0, size = 0;
- struct reg_index_offset rio;
- unsigned char wdata[64];
- unsigned char wri_data[128];
- unsigned char blk_index;
- rt_register_map_t rm;
-
- memcpy(wdata, data, bytes);
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of range\n", reg);
- return -EINVAL;
- }
-
- reg_base = 0;
- rm = rd->props.rm[rio.index + reg_base];
- while (bytes > 0) {
- size = ((bytes <= (rm->size - rio.offset)) ?
- bytes : rm->size - rio.offset);
- if ((rm->reg_type & RT_REG_TYPE_MASK) == RT_VOLATILE) {
- ret = rt_chip_block_write(rd,
- rm->addr + rio.offset,
- size,
- &wdata[count]);
- count += size;
- } else {
- blk_index = (rd->props.rt_regmap_mode &
- RT_IO_BLK_MODE_MASK) >> 3;
-
- ret = rd->rt_block_write[blk_index]
- (rd, rm, size, &rio, wdata, &count);
- if (ret < 0) {
- dev_err(&rd->dev, "rd->rt_block_write fail\n");
- goto ERR;
- }
- }
-
- if ((rm->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE)
- *(rd->cache_flag + rio.index + reg_base) = 1;
-
- bytes -= size;
- if (bytes <= 0)
- goto finished;
- reg_base++;
- rio.offset = 0;
- rm = rd->props.rm[rio.index + reg_base];
- if ((rio.index + reg_base) >= rd->props.register_num) {
- dev_err(&rd->dev, "over regmap size\n");
- goto ERR;
- }
- }
-finished:
- if (rd->props.io_log_en) {
- j = 0;
- for (i = 0; i < count; i++)
- j += sprintf(wri_data + j, "%02x,", wdata[i]);
- pr_info("RT_REGMAP [WRITE] reg0x%04x [Data] 0x%s\n",
- reg, wri_data);
- }
- return 0;
-ERR:
- return -EIO;
-}
-
-static int rt_asyn_cache_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *data)
-{
- int i, j, reg_base, count = 0, ret = 0, size = 0;
- struct reg_index_offset rio;
- unsigned char wdata[64];
- unsigned char wri_data[128];
- unsigned char blk_index;
- rt_register_map_t rm;
-
- memcpy(wdata, data, bytes);
-
- cancel_delayed_work_sync(&rd->rt_work);
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of range\n", reg);
- return -EINVAL;
- }
-
- reg_base = 0;
- rm = rd->props.rm[rio.index + reg_base];
- while (bytes > 0) {
- size = ((bytes <= (rm->size - rio.offset)) ?
- bytes : rm->size - rio.offset);
- if ((rm->reg_type & RT_REG_TYPE_MASK) == RT_VOLATILE) {
- ret = rt_chip_block_write(rd,
- rm->addr + rio.offset,
- size, &wdata[count]);
- count += size;
- } else {
- blk_index = (rd->props.rt_regmap_mode &
- RT_IO_BLK_MODE_MASK) >> 3;
- ret = rd->rt_block_write[blk_index]
- (rd, rm, size, &rio, wdata, &count);
- }
- if (ret < 0) {
- dev_err(&rd->dev, "rd->rt_block_write fail\n");
- goto ERR;
- }
-
- if ((rm->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE) {
- *(rd->cache_flag + rio.index + reg_base) = 1;
- rd->pending_event = 1;
- }
-
- bytes -= size;
- if (bytes <= 0)
- goto finished;
- reg_base++;
- rm = rd->props.rm[rio.index + reg_base];
- rio.offset = 0;
- if ((rio.index + reg_base) >= rd->props.register_num) {
- dev_err(&rd->dev, "over regmap size\n");
- goto ERR;
- }
- }
-finished:
- if (rd->props.io_log_en) {
- j = 0;
- for (i = 0; i < count; i++)
- j += sprintf(wri_data + j, "%02x,", wdata[i]);
- pr_info("RT_REGMAP [WRITE] reg0x%04x [Data] 0x%s\n",
- reg, wri_data);
- }
-
- schedule_delayed_work(&rd->rt_work, msecs_to_jiffies(1));
- return 0;
-ERR:
- return -EIO;
-}
-
-static int rt_block_write_blk_all(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count)
-{
- int cnt;
-
- cnt = *count;
- cnt += size;
- *count = cnt;
- return 0;
-}
-
-static int rt_block_write_blk_chip(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count)
-{
- int i, cnt;
-
- cnt = *count;
- for (i = rio->offset; i < rio->offset + size; i++) {
- if ((rm->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE)
- rm->cache_data[i] =
- wdata[cnt] & rm->wbit_mask[i];
- cnt++;
- }
- *count = cnt;
- return 0;
-}
-
-static int rt_block_write_blk_cache(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count)
-{
- int ret, cnt;
-
- cnt = *count;
-
- ret = rt_chip_block_write(rd, rm->addr + rio->offset,
- size, &wdata[cnt]);
- if (ret < 0) {
- dev_err(&rd->dev,
- "rt block write fail at 0x%02x\n",
- rm->addr + rio->offset);
- return -EIO;
- }
- cnt += size;
- *count = cnt;
- return 0;
-}
-
-static int rt_block_write(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count)
-{
- int i, ret, cnt, change = 0;
-
- cnt = *count;
-
- for (i = rio->offset; i < size + rio->offset; i++) {
- if ((rm->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE) {
- if (rm->reg_type & RT_WR_ONCE) {
- if (rm->cache_data[i] !=
- (wdata[cnt] & rm->wbit_mask[i]))
- change++;
- }
- rm->cache_data[i] = wdata[cnt] & rm->wbit_mask[i];
- }
- cnt++;
- }
-
- if (!change && (rm->reg_type & RT_WR_ONCE))
- goto finish;
-
- if ((rd->props.rt_regmap_mode & RT_CACHE_MODE_MASK) ==
- RT_CACHE_WR_THROUGH) {
- ret = rt_chip_block_write(rd,
- rm->addr + rio->offset,
- size, rm->cache_data);
- if (ret < 0) {
- dev_err(&rd->dev,
- "rt block write fail at 0x%02x\n",
- rm->addr + rio->offset);
- return -EIO;
- }
- }
-
-finish:
- *count = cnt;
- return 0;
-}
-
-static int (*rt_block_map[])(struct rt_regmap_device *rd,
- struct rt_register *rm, int size,
- const struct reg_index_offset *rio,
- unsigned char *wdata, int *count) = {
- &rt_block_write,
- &rt_block_write_blk_all,
- &rt_block_write_blk_cache,
- &rt_block_write_blk_chip,
-};
-
-static int rt_cache_block_read(struct rt_regmap_device *rd, u32 reg,
- int bytes, void *dest)
-{
- int i, ret, count = 0, reg_base = 0, total_bytes = 0;
- struct reg_index_offset rio;
- rt_register_map_t rm;
- unsigned char data[100];
- unsigned char tmp_data[32];
-
- rio = find_register_index(rd, reg);
- if (rio.index < 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of range\n", reg);
- return -EINVAL;
- }
-
- rm = rd->props.rm[rio.index];
-
- total_bytes += (rm->size - rio.offset);
-
- for (i = rio.index + 1; i < rd->props.register_num; i++)
- total_bytes += rd->props.rm[i]->size;
-
- if (bytes > total_bytes) {
- dev_err(&rd->dev, "out of cache map range\n");
- return -EINVAL;
- }
-
- memcpy(data, &rm->cache_data[rio.offset], bytes);
-
- if ((rm->reg_type & RT_REG_TYPE_MASK) == RT_VOLATILE) {
- ret = rd->rops->read_device(rd->client,
- rm->addr, rm->size, tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev,
- "rt_regmap Error at 0x%02x\n",
- rm->addr);
- return -EIO;
- }
- for (i = rio.offset; i < rm->size; i++) {
- data[count] = tmp_data[i];
- count++;
- }
- } else {
- count += (rm->size - rio.offset);
- }
-
- while (count < bytes) {
- reg_base++;
- rm = rd->props.rm[rio.index + reg_base];
- if ((rm->reg_type & RT_REG_TYPE_MASK) == RT_VOLATILE) {
- ret = rd->rops->read_device(rd->client,
- rm->addr, rm->size, &data[count]);
- if (ret < 0) {
- dev_err(&rd->dev,
- "rt_regmap Error at 0x%02x\n",
- rm->addr);
- return -EIO;
- }
- }
- count += rm->size;
- }
-
- if (rd->props.io_log_en)
- pr_info("RT_REGMAP [READ] reg0x%04x\n", reg);
-
- memcpy(dest, data, bytes);
-
- return 0;
-}
-
-/* rt_regmap_cache_backup - back up all cache register value*/
-void rt_regmap_cache_backup(struct rt_regmap_device *rd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- int i;
-
- down(&rd->semaphore);
- for (i = 0; i < rd->props.register_num; i++)
- if ((rm[i]->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE)
- *(rd->cache_flag + i) = 1;
- rd->pending_event = 1;
- up(&rd->semaphore);
-}
-EXPORT_SYMBOL(rt_regmap_cache_backup);
-
-/* _rt_regmap_reg_write - write data to specific register map
- * only support 1, 2, 4 bytes regisetr map
- * @rd: rt_regmap_device pointer.
- * @rrd: rt_reg_data pointer.
- */
-int _rt_regmap_reg_write(struct rt_regmap_device *rd,
- struct rt_reg_data *rrd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- struct reg_index_offset rio;
- int ret, tmp_data;
-
- rio = find_register_index(rd, rrd->reg);
- if (rio.index < 0 || rio.offset != 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of regmap\n", rrd->reg);
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- switch (rm[rio.index]->size) {
- case 1:
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, 1, &rrd->rt_data.data_u8);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- up(&rd->semaphore);
- return -EIO;
- }
- break;
- case 2:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be16_to_cpu(rrd->rt_data.data_u32);
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- up(&rd->semaphore);
- return -EIO;
- }
- break;
- case 3:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN) {
- tmp_data = be32_to_cpu(rrd->rt_data.data_u32);
- tmp_data >>= 8;
- }
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- up(&rd->semaphore);
- return -EIO;
- }
- break;
- case 4:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be32_to_cpu(rrd->rt_data.data_u32);
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- up(&rd->semaphore);
- return -EIO;
- }
- break;
- default:
- dev_err(&rd->dev,
- "Failed: only support 1~4 bytes regmap write\n");
- break;
- }
- up(&rd->semaphore);
- return 0;
-}
-EXPORT_SYMBOL(_rt_regmap_reg_write);
-
-/* _rt_asyn_regmap_reg_write - asyn write data to specific register map*/
-int _rt_asyn_regmap_reg_write(struct rt_regmap_device *rd,
- struct rt_reg_data *rrd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- struct reg_index_offset rio;
- int ret, tmp_data;
-
- rio = find_register_index(rd, rrd->reg);
- if (rio.index < 0 || rio.offset != 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of regmap\n", rrd->reg);
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- switch (rm[rio.index]->size) {
- case 1:
- ret = rt_asyn_cache_block_write(rd,
- rrd->reg, 1,
- &rrd->rt_data.data_u8);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- ret = -EIO;
- goto err_regmap_write;
- }
- break;
- case 2:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be16_to_cpu(rrd->rt_data.data_u32);
- ret = rt_asyn_cache_block_write(rd,
- rrd->reg,
- rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- ret = -EIO;
- goto err_regmap_write;
- }
- break;
- case 3:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN) {
- tmp_data = be32_to_cpu(rrd->rt_data.data_u32);
- tmp_data >>= 8;
- }
- ret = rt_asyn_cache_block_write(rd,
- rrd->reg,
- rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- ret = -EIO;
- goto err_regmap_write;
- }
- break;
- case 4:
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be32_to_cpu(rrd->rt_data.data_u32);
- ret = rt_asyn_cache_block_write(rd,
- rrd->reg,
- rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- ret = -EIO;
- goto err_regmap_write;
- }
- break;
- default:
- dev_err(&rd->dev,
- "Failed: only support 1~4 bytes regmap write\n");
- break;
- }
- up(&rd->semaphore);
- return 0;
-err_regmap_write:
- up(&rd->semaphore);
- return ret;
-}
-EXPORT_SYMBOL(_rt_asyn_regmap_reg_write);
-
-/* _rt_regmap_update_bits - assign bits specific register map */
-int _rt_regmap_update_bits(struct rt_regmap_device *rd,
- struct rt_reg_data *rrd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- struct reg_index_offset rio;
- int ret, new, old;
- bool change = false;
-
- rio = find_register_index(rd, rrd->reg);
- if (rio.index < 0 || rio.offset != 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of regmap\n", rrd->reg);
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- switch (rm[rio.index]->size) {
- case 1:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, 1, &old);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_update_bits;
- }
- new = (old & ~(rrd->mask)) | (rrd->rt_data.data_u8 & rrd->mask);
- change = old != new;
-
- if (((rm[rio.index]->reg_type & RT_WR_ONCE) && change) ||
- !(rm[rio.index]->reg_type & RT_WR_ONCE)) {
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, 1, &new);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- goto err_update_bits;
- }
- }
- break;
- case 2:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &old);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_update_bits;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- old = be16_to_cpu(old);
-
- new = (old & ~(rrd->mask)) |
- (rrd->rt_data.data_u16 & rrd->mask);
-
- change = old != new;
- if (((rm[rio.index]->reg_type & RT_WR_ONCE) && change) ||
- !(rm[rio.index]->reg_type & RT_WR_ONCE)) {
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- new = be16_to_cpu(new);
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &new);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- goto err_update_bits;
- }
- }
- break;
- case 3:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &old);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_update_bits;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN) {
- old = be32_to_cpu(old);
- old >>= 8;
- }
-
- new = (old & ~(rrd->mask)) |
- (rrd->rt_data.data_u32 & rrd->mask);
- change = old != new;
- if (((rm[rio.index]->reg_type & RT_WR_ONCE) && change) ||
- !(rm[rio.index]->reg_type & RT_WR_ONCE)) {
- if (rd->props.rt_format == RT_LITTLE_ENDIAN) {
- new <<= 8;
- new = be32_to_cpu(new);
- }
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &new);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- goto err_update_bits;
- }
- }
- break;
- case 4:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &old);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_update_bits;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- old = be32_to_cpu(old);
-
- new = (old & ~(rrd->mask)) |
- (rrd->rt_data.data_u32 & rrd->mask);
- change = old != new;
- if (((rm[rio.index]->reg_type & RT_WR_ONCE) && change) ||
- !(rm[rio.index]->reg_type & RT_WR_ONCE)) {
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- new = be32_to_cpu(new);
- ret = rd->regmap_ops.regmap_block_write(rd,
- rrd->reg, rm[rio.index]->size, &new);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block write fail\n");
- goto err_update_bits;
- }
- }
- break;
- default:
- dev_err(&rd->dev,
- "Failed: only support 1~4 bytes regmap write\n");
- break;
- }
- up(&rd->semaphore);
- return change;
-err_update_bits:
- up(&rd->semaphore);
- return ret;
-}
-EXPORT_SYMBOL(_rt_regmap_update_bits);
-
-/* rt_regmap_block_write - block write data to register
- * @rd: rt_regmap_device pointer
- * @reg: register address
- * bytes: leng for write
- * src: source data
- */
-int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *src)
-{
- int ret;
-
- down(&rd->semaphore);
- ret = rd->regmap_ops.regmap_block_write(rd, reg, bytes, src);
- up(&rd->semaphore);
- return ret;
-};
-EXPORT_SYMBOL(rt_regmap_block_write);
-
-/* rt_asyn_regmap_block_write - asyn block write*/
-int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg,
- int bytes, const void *src)
-{
- int ret;
-
- down(&rd->semaphore);
- ret = rt_asyn_cache_block_write(rd, reg, bytes, src);
- up(&rd->semaphore);
- return ret;
-};
-EXPORT_SYMBOL(rt_asyn_regmap_block_write);
-
-/* rt_regmap_block_read - block read data form register
- * @rd: rt_regmap_device pointer
- * @reg: register address
- * @bytes: read length
- * @dst: destination for read data
- */
-int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg,
- int bytes, void *dst)
-{
- int ret;
-
- down(&rd->semaphore);
- ret = rd->regmap_ops.regmap_block_read(rd, reg, bytes, dst);
- up(&rd->semaphore);
- return ret;
-};
-EXPORT_SYMBOL(rt_regmap_block_read);
-
-/* _rt_regmap_reg_read - register read for specific register map
- * only support 1, 2, 4 bytes register map.
- * @rd: rt_regmap_device pointer.
- * @rrd: rt_reg_data pointer.
- */
-int _rt_regmap_reg_read(struct rt_regmap_device *rd, struct rt_reg_data *rrd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- struct reg_index_offset rio;
- int ret, tmp_data = 0;
-
- rio = find_register_index(rd, rrd->reg);
- if (rio.index < 0 || rio.offset != 0) {
- dev_err(&rd->dev, "reg 0x%02x is out of regmap\n", rrd->reg);
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- switch (rm[rio.index]->size) {
- case 1:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, 1, &rrd->rt_data.data_u8);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_regmap_reg_read;
- }
- break;
- case 2:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_regmap_reg_read;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be16_to_cpu(tmp_data);
- rrd->rt_data.data_u16 = tmp_data;
- break;
- case 3:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_regmap_reg_read;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be32_to_cpu(tmp_data);
- rrd->rt_data.data_u32 = (tmp_data >> 8);
- break;
- case 4:
- ret = rd->regmap_ops.regmap_block_read(rd,
- rrd->reg, rm[rio.index]->size, &tmp_data);
- if (ret < 0) {
- dev_err(&rd->dev, "rt regmap block read fail\n");
- goto err_regmap_reg_read;
- }
- if (rd->props.rt_format == RT_LITTLE_ENDIAN)
- tmp_data = be32_to_cpu(tmp_data);
- rrd->rt_data.data_u32 = tmp_data;
- break;
- default:
- dev_err(&rd->dev,
- "Failed: only support 1~4 bytes regmap read\n");
- break;
- }
- up(&rd->semaphore);
- return 0;
-err_regmap_reg_read:
- up(&rd->semaphore);
- return ret;
-}
-EXPORT_SYMBOL(_rt_regmap_reg_read);
-
-void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf)
-{
- down(&rd->semaphore);
- sprintf(buf, "%s\n", rd->err_msg);
- up(&rd->semaphore);
-}
-EXPORT_SYMBOL(rt_cache_getlasterror);
-
-void rt_cache_clrlasterror(struct rt_regmap_device *rd)
-{
- down(&rd->semaphore);
- rd->error_occurred = 0;
- sprintf(rd->err_msg, "%s", "No Error");
- up(&rd->semaphore);
-}
-EXPORT_SYMBOL(rt_cache_clrlasterror);
-
-/* initialize cache data from rt_register */
-int rt_regmap_cache_init(struct rt_regmap_device *rd)
-{
- int i, j, ret, bytes_num = 0, count = 0;
- const rt_register_map_t *rm = rd->props.rm;
-
- dev_info(&rd->dev, "rt register cache data init\n");
-
- down(&rd->semaphore);
- rd->cache_flag = devm_kzalloc(&rd->dev,
- rd->props.register_num * sizeof(int), GFP_KERNEL);
-
- if (!rd->props.group) {
- rd->props.group = devm_kzalloc(&rd->dev,
- sizeof(*rd->props.group), GFP_KERNEL);
- rd->props.group[0].start = 0x00;
- rd->props.group[0].end = 0xffff;
- rd->props.group[0].mode = RT_1BYTE_MODE;
- }
-
- /* calculate maxima size for showing on regs debugfs node*/
- rd->part_size_limit = 0;
- for (i = 0; i < rd->props.register_num; i++) {
- if (!rm[i]->cache_data)
- bytes_num += rm[i]->size;
- if (rm[i]->size > rd->part_size_limit &&
- (rm[i]->reg_type & RT_REG_TYPE_MASK) != RT_RESERVE)
- rd->part_size_limit = rm[i]->size;
- }
- rd->part_size_limit = 400 / ((rd->part_size_limit - 1) * 3 + 5);
-
- rd->alloc_data =
- devm_kzalloc(&rd->dev,
- bytes_num * sizeof(unsigned char), GFP_KERNEL);
- if (!rd->alloc_data) {
- pr_info("tmp data memory allocate fail\n");
- goto mem_err;
- }
-
- /* reload cache data from real chip */
- for (i = 0; i < rd->props.register_num; i++) {
- if (!rm[i]->cache_data) {
- rm[i]->cache_data = rd->alloc_data + count;
- count += rm[i]->size;
- if ((rm[i]->reg_type & RT_REG_TYPE_MASK) !=
- RT_VOLATILE) {
- ret = rd->rops->read_device(rd->client,
- rm[i]->addr, rm[i]->size,
- rm[i]->cache_data);
- if (ret < 0) {
- dev_err(&rd->dev, "chip read fail\n");
- goto io_err;
- }
- } else {
- memset(rm[i]->cache_data, 0x00, rm[i]->size);
- }
- }
- *(rd->cache_flag + i) = 0;
- }
-
- /* set 0xff writeable mask for NORMAL and RESERVE type */
- for (i = 0; i < rd->props.register_num; i++) {
- if ((rm[i]->reg_type & RT_REG_TYPE_MASK) == RT_NORMAL ||
- (rm[i]->reg_type & RT_REG_TYPE_MASK) == RT_RESERVE) {
- for (j = 0; j < rm[i]->size; j++)
- rm[i]->wbit_mask[j] = 0xff;
- }
- }
-
- rd->cache_inited = 1;
- dev_info(&rd->dev, "cache cata init successfully\n");
- up(&rd->semaphore);
- return 0;
-mem_err:
- up(&rd->semaphore);
- return -ENOMEM;
-io_err:
- up(&rd->semaphore);
- return -EIO;
-}
-EXPORT_SYMBOL(rt_regmap_cache_init);
-
-/* rt_regmap_cache_reload - reload cache valuew from real chip*/
-int rt_regmap_cache_reload(struct rt_regmap_device *rd)
-{
- int i, ret;
- const rt_register_map_t *rm = rd->props.rm;
-
- down(&rd->semaphore);
- for (i = 0; i < rd->props.register_num; i++) {
- if ((rm[i]->reg_type & RT_REG_TYPE_MASK) != RT_VOLATILE) {
- ret = rd->rops->read_device(rd->client, rm[i]->addr,
- rm[i]->size, rm[i]->cache_data);
- if (ret < 0) {
- dev_err(&rd->dev, "i2c read fail\n");
- goto io_err;
- }
- *(rd->cache_flag + i) = 0;
- }
- }
- rd->pending_event = 0;
- up(&rd->semaphore);
- dev_info(&rd->dev, "cache data reload\n");
- return 0;
-
-io_err:
- up(&rd->semaphore);
- return -EIO;
-}
-EXPORT_SYMBOL(rt_regmap_cache_reload);
-
-/* rt_regmap_add_debubfs - add user own debugfs node
- * @rd: rt_regmap_devcie pointer.
- * @name: a pointer to a string containing the name of the file to create.
- * @mode: the permission that the file should have.
- * @data: a pointer to something that the caller will want to get to later on.
- * The inode.i_private pointer will point this value on the open() call.
- * @fops: a pointer to a struct file_operations that should be used for
- * this file.
- */
-int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name,
- umode_t mode, void *data,
- const struct file_operations *fops)
-{
-#ifdef CONFIG_DEBUG_FS
- struct dentry *den;
-
- den = debugfs_create_file(name, mode, rd->rt_den, data, fops);
- if (!den)
- return -EINVAL;
-#endif /*CONFIG_DEBUG_FS*/
- return 0;
-}
-EXPORT_SYMBOL(rt_regmap_add_debugfs);
-
-/* release cache data*/
-static void rt_regmap_cache_release(struct rt_regmap_device *rd)
-{
- int i;
- const rt_register_map_t *rm = rd->props.rm;
-
- dev_info(&rd->dev, "cache data release\n");
- for (i = 0; i < rd->props.register_num; i++)
- rm[i]->cache_data = NULL;
- devm_kfree(&rd->dev, rd->alloc_data);
- if (rd->cache_flag)
- devm_kfree(&rd->dev, rd->cache_flag);
- rd->cache_inited = 0;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rt_check_dump_config_file(struct rt_regmap_device *rd,
- long int *reg_dump, int *cnt, char *type)
-{
- char *token, *buf, *tmp_type;
- char PATH[64];
- mm_segment_t fs;
- struct file *fp;
- int ret, tmp_cnt = 0;
-
- buf = devm_kzalloc(&rd->dev, 64 * sizeof(char), GFP_KERNEL);
- sprintf(PATH, "/sdcard/%s_dump_config.txt", rd->props.name);
- fp = filp_open(PATH, O_RDONLY, 0);
- if (IS_ERR(fp)) {
- pr_info("There is no Dump config file in sdcard\n");
- devm_kfree(&rd->dev, buf);
- } else {
- fs = get_fs();
- set_fs(get_ds());
- fp->f_op->read(fp, buf, 64, &fp->f_pos);
- set_fs(fs);
-
- token = strsep(&buf, " ");
- tmp_type = token;
- while (token) {
- ret = kstrtoul(token, 16, ®_dump[tmp_cnt]);
- if (ret == 0)
- tmp_cnt++;
- token = strsep(&buf, " ");
- }
- filp_close(fp, NULL);
- *cnt = tmp_cnt;
- memcpy(type, tmp_type, 16);
- devm_kfree(&rd->dev, buf);
- }
-}
-
-static void rt_show_regs(struct rt_regmap_device *rd, struct seq_file *seq_file)
-{
- int i = 0, k = 0, ret, count = 0, cnt = 0;
- unsigned char regval[512];
- long int reg_dump[64] = {0};
- const rt_register_map_t *rm = rd->props.rm;
- char type[16];
-
- rt_check_dump_config_file(rd, reg_dump, &cnt, type);
- down(&rd->semaphore);
- for (i = 0; i < rd->props.register_num; i++) {
- ret = rd->regmap_ops.regmap_block_read(rd, rm[i]->addr,
- rm[i]->size, ®val[count]);
- count += rm[i]->size;
- if (ret < 0) {
- dev_err(&rd->dev, "regmap block read fail\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg + strlen(rd->err_msg),
- "Error block read fail at 0x%02x\n",
- rm[i]->addr);
- } else {
- sprintf(rd->err_msg,
- "Error block read fail at 0x%02x\n",
- rm[i]->addr);
- rd->error_occurred = 1;
- }
- goto err_show_regs;
- }
-
- if ((rm[i]->reg_type & RT_REG_TYPE_MASK) != RT_RESERVE) {
- seq_printf(seq_file, "reg0x%02x:0x", rm[i]->addr);
- for (k = 0; k < rm[i]->size; k++)
- seq_printf(seq_file, "%02x,",
- regval[count - rm[i]->size + k]);
- seq_puts(seq_file, "\n");
- } else {
- seq_printf(seq_file,
- "reg0x%02x:reserve\n", rm[i]->addr);
- }
- }
-err_show_regs:
- up(&rd->semaphore);
-}
-
-static int general_read(struct seq_file *seq_file, void *_data)
-{
- struct rt_debug_st *st = (struct rt_debug_st *)seq_file->private;
- struct rt_regmap_device *rd = st->info;
- rt_register_map_t rm;
- char lbuf[900];
- unsigned char reg_data[24] = { 0 };
- unsigned char data;
- int i = 0, rc = 0, size = 0;
-
- lbuf[0] = '\0';
- switch (st->id) {
- case RT_DBG_REG:
- seq_printf(seq_file, "0x%04x\n", rd->dbg_data.reg_addr);
- break;
- case RT_DBG_DATA:
- if (rd->dbg_data.reg_size == 0)
- rd->dbg_data.reg_size = 1;
-
- size = rd->dbg_data.reg_size;
-
- if (rd->dbg_data.rio.index == -1) {
- down(&rd->semaphore);
- rc = rt_chip_block_read(rd, rd->dbg_data.reg_addr,
- size, reg_data);
- up(&rd->semaphore);
- if (rc < 0) {
- seq_puts(seq_file, "invalid read\n");
- break;
- }
- goto hiden_read;
- }
-
- rm = rd->props.rm[rd->dbg_data.rio.index];
-
- down(&rd->semaphore);
- rc = rd->regmap_ops.regmap_block_read(rd,
- rd->dbg_data.reg_addr, size, reg_data);
- up(&rd->semaphore);
- if (rc < 0) {
- seq_puts(seq_file, "invalid read\n");
- break;
- }
-
-hiden_read:
- if (®_data[i]) {
- seq_puts(seq_file, "0x");
- for (i = 0; i < size; i++)
- seq_printf(seq_file, "%02x,", reg_data[i]);
- seq_puts(seq_file, "\n");
- }
- break;
- case RT_DBG_ERROR:
- seq_puts(seq_file, "======== Error Message ========\n");
- if (!rd->error_occurred)
- seq_puts(seq_file, "No Error\n");
- else
- seq_printf(seq_file, rd->err_msg);
- break;
- case RT_DBG_REGS:
- rt_show_regs(rd, seq_file);
- break;
- case RT_DBG_NAME:
- seq_printf(seq_file, "%s\n", rd->props.aliases);
- break;
- case RT_DBG_SIZE:
- seq_printf(seq_file, "%d\n", rd->dbg_data.reg_size);
- break;
- case RT_DBG_BLOCK:
- data = rd->props.rt_regmap_mode & RT_IO_BLK_MODE_MASK;
- if (data == RT_IO_PASS_THROUGH)
- seq_puts(seq_file, "0 => IO_PASS_THROUGH\n");
- else if (data == RT_IO_BLK_ALL)
- seq_puts(seq_file, "1 => IO_BLK_ALL\n");
- else if (data == RT_IO_BLK_CACHE)
- seq_puts(seq_file, "2 => IO_BLK_CACHE\n");
- else if (data == RT_IO_BLK_CHIP)
- seq_puts(seq_file, "3 => IO_BLK_CHIP\n");
- break;
- case RT_DBG_SLAVE_ADDR:
- {
- struct i2c_client *i2c = rd->client;
-
- seq_printf(seq_file, "0x%02x\n", i2c->addr);
- }
- break;
- case RT_SUPPORT_MODE:
- seq_puts(seq_file, " == BLOCK MODE ==\n");
- seq_puts(seq_file, "0 => IO_PASS_THROUGH\n");
- seq_puts(seq_file, "1 => IO_BLK_ALL\n");
- seq_puts(seq_file, "2 => IO_BLK_CHIP\n");
- seq_puts(seq_file, "3 => IO_BLK_CACHE\n");
- seq_puts(seq_file, " == CACHE MODE ==\n");
- seq_puts(seq_file, "0 => CACHE_WR_THROUGH\n");
- seq_puts(seq_file, "1 => CACHE_WR_BACK\n");
- seq_puts(seq_file, "2 => CACHE_DISABLE\n");
-
- break;
- case RT_DBG_IO_LOG:
- seq_printf(seq_file, "%d\n", rd->props.io_log_en);
- break;
- case RT_DBG_CACHE_MODE:
- data = rd->props.rt_regmap_mode & RT_CACHE_MODE_MASK;
- if (data == RT_CACHE_WR_THROUGH)
- seq_printf(seq_file, "%s",
- "0 => Cache Write Through\n");
- else if (data == RT_CACHE_WR_BACK)
- seq_printf(seq_file, "%s", "1 => Cache Write Back\n");
- else if (data == RT_CACHE_DISABLE)
- seq_printf(seq_file, "%s", "2 => Cache Disable\n");
- break;
- case RT_DBG_REG_SIZE:
- size = rt_get_regsize(rd, rd->dbg_data.reg_addr);
- if (size < 0)
- seq_printf(seq_file, "%d\n", 0);
- else
- seq_printf(seq_file, "%d\n", size);
- break;
- }
- return 0;
-}
-
-static int general_open(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ)
- return single_open(file, general_read, inode->i_private);
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t general_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct rt_debug_st *st = file->private_data;
- struct rt_regmap_device *rd = st->info;
- struct reg_index_offset rio;
- long int param[5];
- unsigned char reg_data[24] = { 0 };
- int rc, size = 0;
- char lbuf[128];
-
- if (count > sizeof(lbuf) - 1)
- return -EFAULT;
-
- rc = copy_from_user(lbuf, ubuf, count);
- if (rc)
- return -EFAULT;
-
- lbuf[count] = '\0';
-
- switch (st->id) {
- case RT_DBG_REG:
- rc = get_parameters(lbuf, param, 1);
- rio = find_register_index(rd, param[0]);
- down(&rd->semaphore);
- if (rio.index < 0) {
- pr_info("this is an invalid or hiden register\n");
- rd->dbg_data.reg_addr = param[0];
- rd->dbg_data.rio.index = -1;
- } else {
- rd->dbg_data.rio = rio;
- rd->dbg_data.reg_addr = param[0];
- }
- up(&rd->semaphore);
- break;
- case RT_DBG_DATA:
- if (rd->dbg_data.reg_size == 0)
- rd->dbg_data.reg_size = 1;
-
- if (rd->dbg_data.rio.index == -1) {
- size = rd->dbg_data.reg_size;
- if ((size - 1) * 3 + 5 != count) {
- dev_err(&rd->dev, "wrong input length\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg +
- strlen(rd->err_msg),
- "Error, wrong input length\n");
- } else {
- sprintf(rd->err_msg,
- "Error, wrong input length\n");
- rd->error_occurred = 1;
- }
- return -EINVAL;
- }
-
- rc = get_datas((char *)ubuf, count, reg_data, size);
- if (rc < 0) {
- dev_err(&rd->dev, "get datas fail\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg +
- strlen(rd->err_msg),
- "Error, get datas fail\n");
- } else {
- sprintf(rd->err_msg,
- "Error, get datas fail\n");
- rd->error_occurred = 1;
- }
- return -EINVAL;
- }
- down(&rd->semaphore);
- rc = rt_chip_block_write(rd, rd->dbg_data.reg_addr,
- size, reg_data);
- up(&rd->semaphore);
- if (rc < 0) {
- dev_err(&rd->dev, "chip block write fail\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg +
- strlen(rd->err_msg),
- "Error chip block write fail at 0x%02x\n",
- rd->dbg_data.reg_addr);
- } else {
- sprintf(rd->err_msg,
- "Error chip block write fail at 0x%02x\n",
- rd->dbg_data.reg_addr);
- rd->error_occurred = 1;
- }
- return -EIO;
- }
- break;
- }
-
- size = rd->dbg_data.reg_size;
-
- if ((size - 1) * 3 + 5 != count) {
- dev_err(&rd->dev, "wrong input length\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg + strlen(rd->err_msg),
- "Error, wrong input length\n");
- } else {
- sprintf(rd->err_msg,
- "Error, wrong input length\n");
- rd->error_occurred = 1;
- }
- return -EINVAL;
- }
-
- rc = get_datas((char *)ubuf, count, reg_data, size);
- if (rc < 0) {
- dev_err(&rd->dev, "get datas fail\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg + strlen(rd->err_msg),
- "Error, get datas fail\n");
- } else {
- sprintf(rd->err_msg,
- "Error, get datas fail\n");
- rd->error_occurred = 1;
- }
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- rc = rd->regmap_ops.regmap_block_write(rd,
- rd->dbg_data.reg_addr, size, reg_data);
- up(&rd->semaphore);
- if (rc < 0) {
- dev_err(&rd->dev, "regmap block write fail\n");
- if (rd->error_occurred) {
- sprintf(rd->err_msg + strlen(rd->err_msg),
- "Error regmap block write fail at 0x%02x\n",
- rd->dbg_data.reg_addr);
- } else {
- sprintf(rd->err_msg,
- "Error regmap block write fail at 0x%02x\n",
- rd->dbg_data.reg_addr);
- rd->error_occurred = 1;
- }
- return -EIO;
- }
-
- break;
- case RT_DBG_SYNC:
- rc = get_parameters(lbuf, param, 1);
- if (param[0])
- rt_regmap_cache_sync(rd);
- break;
- case RT_DBG_ERROR:
- rc = get_parameters(lbuf, param, 1);
- if (param[0])
- rt_cache_clrlasterror(rd);
- break;
- case RT_DBG_SIZE:
- rc = get_parameters(lbuf, param, 1);
- if (param[0] >= 0) {
- down(&rd->semaphore);
- rd->dbg_data.reg_size = param[0];
- up(&rd->semaphore);
- } else {
- if (rd->error_occurred) {
- sprintf(rd->err_msg + strlen(rd->err_msg),
- "Error, size must > 0\n");
- } else {
- sprintf(rd->err_msg,
- "Error, size must > 0\n");
- rd->error_occurred = 1;
- }
- return -EINVAL;
- }
- break;
- case RT_DBG_BLOCK:
- rc = get_parameters(lbuf, param, 1);
- if (param[0] < 0)
- param[0] = 0;
- else if (param[0] > 3)
- param[0] = 3;
-
- param[0] <<= 3;
-
- down(&rd->semaphore);
- rd->props.rt_regmap_mode &= ~RT_IO_BLK_MODE_MASK;
- rd->props.rt_regmap_mode |= param[0];
- up(&rd->semaphore);
- if (param[0] == RT_IO_PASS_THROUGH)
- rt_regmap_cache_sync(rd);
- break;
- case RT_DBG_IO_LOG:
- rc = get_parameters(lbuf, param, 1);
- down(&rd->semaphore);
- if (!param[0])
- rd->props.io_log_en = 0;
- else
- rd->props.io_log_en = 1;
- up(&rd->semaphore);
- break;
- case RT_DBG_CACHE_MODE:
- rc = get_parameters(lbuf, param, 1);
- if (param[0] < 0)
- param[0] = 0;
- else if (param[0] > 2)
- param[0] = 2;
- param[0] <<= 1;
-
- if (param[0] == RT_CACHE_WR_THROUGH) {
- rt_regmap_cache_reload(rd);
- rd->regmap_ops.regmap_block_write =
- rt_cache_block_write;
- rd->regmap_ops.regmap_block_read = &rt_cache_block_read;
- } else if (param[0] == RT_CACHE_WR_BACK) {
- rt_regmap_cache_reload(rd);
- rd->regmap_ops.regmap_block_write =
- rt_asyn_cache_block_write;
- rd->regmap_ops.regmap_block_read = &rt_cache_block_read;
- } else if (param[0] == RT_CACHE_DISABLE) {
- rd->regmap_ops.regmap_block_write =
- rt_chip_block_write;
- rd->regmap_ops.regmap_block_read = rt_chip_block_read;
- }
-
- rd->props.rt_regmap_mode &= ~RT_CACHE_MODE_MASK;
- rd->props.rt_regmap_mode |= param[0];
-
- break;
- default:
- return -EINVAL;
- }
-
- return count;
-}
-
-static int general_release(struct inode *inode, struct file *file)
-{
- if (file->f_mode & FMODE_READ)
- return single_release(inode, file);
- return 0;
-}
-
-static const struct file_operations general_ops = {
- .owner = THIS_MODULE,
- .open = general_open,
- .write = general_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = general_release,
-};
-
-/* create general debugfs node */
-static void rt_create_general_debug(struct rt_regmap_device *rd,
- struct dentry *dir)
-{
- rd->rtdbg_st[0].info = rd;
- rd->rtdbg_st[0].id = RT_DBG_REG;
- rd->rt_debug_file[0] = debugfs_create_file("reg_addr",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[0],
- &general_ops);
- rd->rtdbg_st[1].info = rd;
- rd->rtdbg_st[1].id = RT_DBG_DATA;
- rd->rt_debug_file[1] = debugfs_create_file("data",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[1],
- &general_ops);
-
- rd->rtdbg_st[2].info = rd;
- rd->rtdbg_st[2].id = RT_DBG_REGS;
- rd->rt_debug_file[2] = debugfs_create_file("regs",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[2],
- &general_ops);
-
- rd->rtdbg_st[3].info = rd;
- rd->rtdbg_st[3].id = RT_DBG_SYNC;
- rd->rt_debug_file[3] = debugfs_create_file("sync",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[3],
- &general_ops);
-
- rd->rtdbg_st[4].info = rd;
- rd->rtdbg_st[4].id = RT_DBG_ERROR;
- rd->rt_debug_file[4] = debugfs_create_file("Error",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[4],
- &general_ops);
-
- rd->rtdbg_st[5].info = rd;
- rd->rtdbg_st[5].id = RT_DBG_NAME;
- rd->rt_debug_file[5] = debugfs_create_file("name",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[5],
- &general_ops);
-
- rd->rtdbg_st[6].info = rd;
- rd->rtdbg_st[6].id = RT_DBG_BLOCK;
- rd->rt_debug_file[6] = debugfs_create_file("block",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[6],
- &general_ops);
-
- rd->rtdbg_st[7].info = rd;
- rd->rtdbg_st[7].id = RT_DBG_SIZE;
- rd->rt_debug_file[7] = debugfs_create_file("size",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[7],
- &general_ops);
-
- rd->rtdbg_st[8].info = rd;
- rd->rtdbg_st[8].id = RT_DBG_SLAVE_ADDR;
- rd->rt_debug_file[8] = debugfs_create_file("slave_addr",
- S_IFREG | 0444, dir,
- (void *)
- &rd->rtdbg_st[8],
- &general_ops);
-
- rd->rtdbg_st[9].info = rd;
- rd->rtdbg_st[9].id = RT_SUPPORT_MODE;
- rd->rt_debug_file[9] = debugfs_create_file("support_mode",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[9],
- &general_ops);
-
- rd->rtdbg_st[10].info = rd;
- rd->rtdbg_st[10].id = RT_DBG_IO_LOG;
- rd->rt_debug_file[10] = debugfs_create_file("io_log",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[10],
- &general_ops);
-
- rd->rtdbg_st[11].info = rd;
- rd->rtdbg_st[11].id = RT_DBG_CACHE_MODE;
- rd->rt_debug_file[11] = debugfs_create_file("cache_mode",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[11],
- &general_ops);
- rd->rtdbg_st[12].info = rd;
- rd->rtdbg_st[12].id = RT_DBG_REG_SIZE;
- rd->rt_debug_file[12] = debugfs_create_file("reg_size",
- S_IFREG | 0444, dir,
- (void *)&rd->rtdbg_st[12],
- &general_ops);
-}
-
-static int eachreg_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t eachreg_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct rt_debug_st *st = file->private_data;
- struct rt_regmap_device *rd = st->info;
- rt_register_map_t rm = rd->props.rm[st->id];
- int rc;
- unsigned char pars[20];
-
- if ((rm->size - 1) * 3 + 5 != count) {
- dev_err(&rd->dev, "wrong input length\n");
- return -EINVAL;
- }
- rc = get_datas((char *)ubuf, count, pars, rm->size);
- if (rc < 0) {
- dev_err(&rd->dev, "get datas fail\n");
- return -EINVAL;
- }
-
- down(&rd->semaphore);
- rc = rd->regmap_ops.regmap_block_write(rd, rm->addr,
- rm->size, &pars[0]);
- up(&rd->semaphore);
- if (rc < 0) {
- dev_err(&rd->dev, "regmap block read fail\n");
- return -EIO;
- }
-
- return count;
-}
-
-static ssize_t eachreg_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct rt_debug_st *st = file->private_data;
- struct rt_regmap_device *rd = st->info;
- char lbuf[80];
- unsigned char regval[32];
- rt_register_map_t rm = rd->props.rm[st->id];
- int i, j = 0, rc;
-
- lbuf[0] = '\0';
-
- down(&rd->semaphore);
- rc = rd->regmap_ops.regmap_block_read(rd, rm->addr, rm->size, regval);
- up(&rd->semaphore);
- if (rc < 0) {
- dev_err(&rd->dev, "regmap block read fail\n");
- return -EIO;
- }
-
- j += sprintf(lbuf + j, "reg0x%02x:0x", rm->addr);
- for (i = 0; i < rm->size; i++)
- j += sprintf(lbuf + j, "%02x,", regval[i]);
- j += sprintf(lbuf + j, "\n");
-
- return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf));
-}
-
-static const struct file_operations eachreg_ops = {
- .open = eachreg_open,
- .read = eachreg_read,
- .write = eachreg_write,
-};
-
-/* create every register node at debugfs */
-static void rt_create_every_debug(struct rt_regmap_device *rd,
- struct dentry *dir)
-{
- int i;
- char buf[10];
-
- rd->rt_reg_file = devm_kzalloc(&rd->dev,
- rd->props.register_num * sizeof(struct dentry *), GFP_KERNEL);
- rd->reg_st = devm_kzalloc(&rd->dev,
- rd->props.register_num * sizeof(struct rt_debug_st *),
- GFP_KERNEL);
- for (i = 0; i < rd->props.register_num; i++) {
- sprintf(buf, "reg0x%02x", (rd->props.rm[i])->addr);
- rd->rt_reg_file[i] = devm_kzalloc(&rd->dev,
- sizeof(rd->rt_reg_file[i]),
- GFP_KERNEL);
- rd->reg_st[i] =
- devm_kzalloc(&rd->dev, sizeof(rd->reg_st[i]), GFP_KERNEL);
-
- rd->reg_st[i]->info = rd;
- rd->reg_st[i]->id = i;
- rd->rt_reg_file[i] = debugfs_create_file(buf,
- S_IFREG | 0444, dir,
- (void *)rd->reg_st[i],
- &eachreg_ops);
- }
-}
-
-static void rt_release_every_debug(struct rt_regmap_device *rd)
-{
- int num = rd->props.register_num;
- int i;
-
- for (i = 0; i < num; i++) {
- devm_kfree(&rd->dev, rd->rt_reg_file[i]);
- devm_kfree(&rd->dev, rd->reg_st[i]);
- }
- devm_kfree(&rd->dev, rd->rt_reg_file);
- devm_kfree(&rd->dev, rd->reg_st);
-}
-#endif /* CONFIG_DEBUG_FS */
-
-static void rt_regmap_device_release(struct device *dev)
-{
- struct rt_regmap_device *rd = to_rt_regmap_device(dev);
-
- devm_kfree(dev, rd);
-}
-
-/* check the rt_register format is correct */
-static int rt_regmap_check(struct rt_regmap_device *rd)
-{
- const rt_register_map_t *rm = rd->props.rm;
- int num = rd->props.register_num;
- int i;
-
- /* check name property */
- if (!rd->props.name) {
- pr_info("there is no node name for rt-regmap\n");
- return -EINVAL;
- }
-
- if (!(rd->props.rt_regmap_mode & RT_BYTE_MODE_MASK))
- goto single_byte;
-
- for (i = 0; i < num; i++) {
- /* check byte size, 1 byte ~ 24 bytes is valid */
- if (rm[i]->size < 1 || rm[i]->size > 24) {
- pr_info("rt register size error at reg 0x%02x\n",
- rm[i]->addr);
- return -EINVAL;
- }
- }
-
- for (i = 0; i < num - 1; i++) {
- /* check register sequence */
- if (rm[i]->addr >= rm[i + 1]->addr) {
- pr_info("sequence format error at reg 0x%02x\n",
- rm[i]->addr);
- return -EINVAL;
- }
- }
-
-single_byte:
- /* no default reg_addr and reister_map first addr is not 0x00 */
- if (!rd->dbg_data.reg_addr && rm[0]->addr) {
- rd->dbg_data.reg_addr = rm[0]->addr;
- rd->dbg_data.rio.index = 0;
- rd->dbg_data.rio.offset = 0;
- }
- return 0;
-}
-
-static int rt_create_simple_map(struct rt_regmap_device *rd)
-{
- int i, j, count = 0, num = 0;
- rt_register_map_t *rm;
-
- pr_info("%s\n", __func__);
- for (i = 0; i < rd->props.register_num; i++)
- num += rd->props.rm[i]->size;
-
- rm = devm_kzalloc(&rd->dev, num * sizeof(*rm), GFP_KERNEL);
-
- for (i = 0; i < rd->props.register_num; i++) {
- for (j = 0; j < rd->props.rm[i]->size; j++) {
- rm[count] = devm_kzalloc(&rd->dev,
- sizeof(struct rt_register),
- GFP_KERNEL);
- rm[count]->wbit_mask = devm_kzalloc(&rd->dev,
- sizeof(unsigned char), GFP_KERNEL);
-
- rm[count]->addr = rd->props.rm[i]->addr + j;
- rm[count]->size = 1;
- rm[count]->reg_type = rd->props.rm[i]->reg_type;
- if ((rd->props.rm[i]->reg_type & RT_REG_TYPE_MASK) !=
- RT_WBITS)
- rm[count]->wbit_mask[0] = 0xff;
- else
- rm[count]->wbit_mask[0] =
- rd->props.rm[i]->wbit_mask[0];
- count++;
- }
- if (count > num)
- break;
- }
-
- rd->props.register_num = num;
- rd->props.rm = rm;
-
- return 0;
-}
-
-/* rt_regmap_device_register
- * @props: a pointer to rt_regmap_properties for rt_regmap_device
- * @rops: a pointer to rt_regmap_fops for rt_regmap_device
- * @parent: a pinter to parent device
- * @client: a pointer to the slave client of this device
- * @drvdata: a pointer to the driver data
- */
-struct rt_regmap_device *rt_regmap_device_register
- (struct rt_regmap_properties *props,
- struct rt_regmap_fops *rops,
- struct device *parent,
- void *client, void *drvdata)
-{
- struct rt_regmap_device *rd;
- int ret = 0, i;
- char device_name[32];
- unsigned char data;
-
- pr_info("regmap_device_register: name = %s\n", props->name);
- rd = devm_kzalloc(parent, sizeof(*rd), GFP_KERNEL);
- if (!rd) {
- pr_info("rt_regmap_device memory allocate fail\n");
- return NULL;
- }
-
- /* create a binary semaphore */
- sema_init(&rd->semaphore, 1);
- rd->dev.parent = parent;
- rd->client = client;
- rd->dev.release = rt_regmap_device_release;
- dev_set_drvdata(&rd->dev, drvdata);
- sprintf(device_name, "rt_regmap_%s", props->name);
- dev_set_name(&rd->dev, device_name);
- if (props)
- memcpy(&rd->props, props, sizeof(struct rt_regmap_properties));
-
- /* check rt_registe_map format */
- ret = rt_regmap_check(rd);
- if (ret) {
- pr_info("rt register map format error\n");
- devm_kfree(parent, rd);
- return NULL;
- }
-
- ret = device_register(&rd->dev);
- if (ret) {
- pr_info("rt-regmap dev register fail\n");
- devm_kfree(parent, rd);
- return NULL;
- }
-
- rd->rops = rops;
- rd->err_msg = devm_kzalloc(parent, 128 * sizeof(char), GFP_KERNEL);
-
- if (!(rd->props.rt_regmap_mode & RT_BYTE_MODE_MASK)) {
- ret = rt_create_simple_map(rd);
- if (ret < 0) {
- pr_info(" rt create simple register map fail\n");
- goto err_cacheinit;
- }
- }
-
- /* init cache data */
- ret = rt_regmap_cache_init(rd);
- if (ret < 0) {
- pr_info(" rt cache data init fail\n");
- goto err_cacheinit;
- }
-
- INIT_DELAYED_WORK(&rd->rt_work, rt_work_func);
-
- for (i = 0; i <= 3; i++)
- rd->rt_block_write[i] = rt_block_map[i];
-
- data = rd->props.rt_regmap_mode & RT_CACHE_MODE_MASK;
- if (data == RT_CACHE_WR_THROUGH) {
- rd->regmap_ops.regmap_block_write = &rt_cache_block_write;
- rd->regmap_ops.regmap_block_read = &rt_cache_block_read;
- } else if (data == RT_CACHE_WR_BACK) {
- rd->regmap_ops.regmap_block_write = &rt_asyn_cache_block_write;
- rd->regmap_ops.regmap_block_read = &rt_cache_block_read;
- } else if (data == RT_CACHE_DISABLE) {
- rd->regmap_ops.regmap_block_write = &rt_chip_block_write;
- rd->regmap_ops.regmap_block_read = &rt_chip_block_read;
- }
-
-#ifdef CONFIG_DEBUG_FS
- rd->rt_den = debugfs_create_dir(props->name, rt_regmap_dir);
- if (!IS_ERR(rd->rt_den)) {
- rt_create_general_debug(rd, rd->rt_den);
- if (rd->props.rt_regmap_mode & DBG_MODE_MASK)
- rt_create_every_debug(rd, rd->rt_den);
- } else {
- goto err_debug;
- }
-#endif /* CONFIG_DEBUG_FS */
-
- return rd;
-
-#ifdef CONFIG_DEBUG_FS
-err_debug:
- rt_regmap_cache_release(rd);
-#endif /* CONFIG_DEBUG_FS */
-err_cacheinit:
- device_unregister(&rd->dev);
- return NULL;
-}
-EXPORT_SYMBOL(rt_regmap_device_register);
-
-/* rt_regmap_device_unregister - unregister rt_regmap_device*/
-void rt_regmap_device_unregister(struct rt_regmap_device *rd)
-{
- if (!rd)
- return;
- down(&rd->semaphore);
- rd->rops = NULL;
- up(&rd->semaphore);
- if (rd->cache_inited)
- rt_regmap_cache_release(rd);
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(rd->rt_den);
- if (rd->props.rt_regmap_mode & DBG_MODE_MASK)
- rt_release_every_debug(rd);
-#endif /* CONFIG_DEBUG_FS */
- device_unregister(&rd->dev);
-}
-EXPORT_SYMBOL(rt_regmap_device_unregister);
-
-static int __init regmap_plat_init(void)
-{
- rt_regmap_dir = debugfs_create_dir("rt-regmap", 0);
- pr_info("Init Richtek RegMap\n");
- if (IS_ERR(rt_regmap_dir)) {
- pr_err("rt-regmap debugfs node create fail\n");
- return -EINVAL;
- }
- return 0;
-}
-
-subsys_initcall(regmap_plat_init);
-
-static void __exit regmap_plat_exit(void)
-{
- debugfs_remove(rt_regmap_dir);
-}
-
-module_exit(regmap_plat_exit);
-
-MODULE_DESCRIPTION("Richtek regmap Driver");
-MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
-MODULE_VERSION(RT_REGMAP_VERSION);
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Richtek RT1711H Type-C Port Control Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/semaphore.h>
-#include <linux/pm_runtime.h>
-#include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/cpu.h>
-#include <linux/version.h>
-#include <linux/sched/clock.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-#include <linux/hisi/log/hisi_log.h>
-
-#ifdef CONFIG_RT_REGMAP
-#include <linux/hisi/usb/pd/richtek/rt-regmap.h>
-#endif /* CONFIG_RT_REGMAP */
-#include <linux/sched/rt.h>
-
-/* #define DEBUG_GPIO 66 */
-
-#define RT1711H_DRV_VERSION "1.1.8_G"
-
-struct rt1711_chip {
- struct i2c_client *client;
- struct device *dev;
-#ifdef CONFIG_RT_REGMAP
- struct rt_regmap_device *m_dev;
-#endif /* CONFIG_RT_REGMAP */
- struct semaphore io_lock;
- struct semaphore suspend_lock;
- struct tcpc_desc *tcpc_desc;
- struct tcpc_device *tcpc;
- struct kthread_worker irq_worker;
- struct kthread_work irq_work;
- struct task_struct *irq_worker_task;
-
- atomic_t poll_count;
- struct delayed_work poll_work;
-
- int irq_gpio;
- int irq;
- int chip_id;
-};
-
-#ifdef CONFIG_RT_REGMAP
-RT_REG_DECL(TCPC_V10_REG_VID, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_PID, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_DID, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TYPEC_REV, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_PD_REV, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_PDIF_REV, 2, RT_VOLATILE, {});
-
-RT_REG_DECL(TCPC_V10_REG_ALERT, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_ALERT_MASK, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_POWER_STATUS_MASK, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_FAULT_STATUS_MASK, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TCPC_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_ROLE_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_FAULT_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_POWER_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_CC_STATUS, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_POWER_STATUS, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_FAULT_STATUS, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_COMMAND, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_MSG_HDR_INFO, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_RX_DETECT, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_RX_BYTE_CNT, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_RX_BUF_FRAME_TYPE, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_RX_HDR, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_RX_DATA, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TRANSMIT, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TX_BYTE_CNT, 1, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TX_HDR, 2, RT_VOLATILE, {});
-RT_REG_DECL(TCPC_V10_REG_TX_DATA, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_CLK_CTRL2, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_CLK_CTRL3, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_BMC_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_BMCIO_RXDZSEL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_RT_STATUS, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_RT_INT, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_RT_MASK, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_IDLE_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_INTRST_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_WATCHDOG_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_I2CRST_CTRL, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_SWRESET, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_TTCPC_FILTER, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_DRP_TOGGLE_CYCLE, 1, RT_VOLATILE, {});
-RT_REG_DECL(RT1711H_REG_DRP_DUTY_CTRL, 1, RT_VOLATILE, {});
-
-static const rt_register_map_t rt1711_chip_regmap[] = {
- RT_REG(TCPC_V10_REG_VID),
- RT_REG(TCPC_V10_REG_PID),
- RT_REG(TCPC_V10_REG_DID),
- RT_REG(TCPC_V10_REG_TYPEC_REV),
- RT_REG(TCPC_V10_REG_PD_REV),
- RT_REG(TCPC_V10_REG_PDIF_REV),
- RT_REG(TCPC_V10_REG_ALERT),
- RT_REG(TCPC_V10_REG_ALERT_MASK),
- RT_REG(TCPC_V10_REG_POWER_STATUS_MASK),
- RT_REG(TCPC_V10_REG_FAULT_STATUS_MASK),
- RT_REG(TCPC_V10_REG_TCPC_CTRL),
- RT_REG(TCPC_V10_REG_ROLE_CTRL),
- RT_REG(TCPC_V10_REG_FAULT_CTRL),
- RT_REG(TCPC_V10_REG_POWER_CTRL),
- RT_REG(TCPC_V10_REG_CC_STATUS),
- RT_REG(TCPC_V10_REG_POWER_STATUS),
- RT_REG(TCPC_V10_REG_FAULT_STATUS),
- RT_REG(TCPC_V10_REG_COMMAND),
- RT_REG(TCPC_V10_REG_MSG_HDR_INFO),
- RT_REG(TCPC_V10_REG_RX_DETECT),
- RT_REG(TCPC_V10_REG_RX_BYTE_CNT),
- RT_REG(TCPC_V10_REG_RX_BUF_FRAME_TYPE),
- RT_REG(TCPC_V10_REG_RX_HDR),
- RT_REG(TCPC_V10_REG_RX_DATA),
- RT_REG(TCPC_V10_REG_TRANSMIT),
- RT_REG(TCPC_V10_REG_TX_BYTE_CNT),
- RT_REG(TCPC_V10_REG_TX_HDR),
- RT_REG(TCPC_V10_REG_TX_DATA),
- RT_REG(RT1711H_REG_CLK_CTRL2),
- RT_REG(RT1711H_REG_CLK_CTRL3),
- RT_REG(RT1711H_REG_BMC_CTRL),
- RT_REG(RT1711H_REG_BMCIO_RXDZSEL),
- RT_REG(RT1711H_REG_RT_STATUS),
- RT_REG(RT1711H_REG_RT_INT),
- RT_REG(RT1711H_REG_RT_MASK),
- RT_REG(RT1711H_REG_IDLE_CTRL),
- RT_REG(RT1711H_REG_INTRST_CTRL),
- RT_REG(RT1711H_REG_WATCHDOG_CTRL),
- RT_REG(RT1711H_REG_I2CRST_CTRL),
- RT_REG(RT1711H_REG_SWRESET),
- RT_REG(RT1711H_REG_TTCPC_FILTER),
- RT_REG(RT1711H_REG_DRP_TOGGLE_CYCLE),
- RT_REG(RT1711H_REG_DRP_DUTY_CTRL),
-};
-
-#define RT1711_CHIP_REGMAP_SIZE ARRAY_SIZE(rt1711_chip_regmap)
-
-#endif /* CONFIG_RT_REGMAP */
-
-static int rt1711_read_device(void *client, u32 reg, int len, void *dst)
-{
- struct i2c_client *i2c = (struct i2c_client *)client;
- int ret = 0, count = 5;
-
- while (count) {
- if (len > 1) {
- ret = i2c_smbus_read_i2c_block_data(i2c, reg, len, dst);
- if (ret < 0)
- count--;
- else
- return ret;
- } else {
- ret = i2c_smbus_read_byte_data(i2c, reg);
- if (ret < 0) {
- count--;
- } else {
- *(u8 *)dst = (u8)ret;
- return ret;
- }
- }
- usleep_range(100, 120);
- }
- return ret;
-}
-
-static int rt1711_write_device(void *client, u32 reg, int len, const void *src)
-{
- const u8 *data;
- struct i2c_client *i2c = (struct i2c_client *)client;
- int ret = 0, count = 5;
-
- while (count) {
- if (len > 1) {
- ret = i2c_smbus_write_i2c_block_data(
- i2c, reg, len, src);
- if (ret < 0)
- count--;
- else
- return ret;
- } else {
- data = src;
- ret = i2c_smbus_write_byte_data(i2c, reg, *data);
- if (ret < 0)
- count--;
- else
- return ret;
- }
- usleep_range(100, 120);
- }
- return ret;
-}
-
-static int rt1711_reg_read(struct i2c_client *i2c, u8 reg)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(i2c);
- u8 val = 0;
- int ret = 0;
-
-#ifdef CONFIG_RT_REGMAP
- ret = rt_regmap_block_read(chip->m_dev, reg, 1, &val);
-#else
- ret = rt1711_read_device(chip->client, reg, 1, &val);
-#endif /* CONFIG_RT_REGMAP */
- if (ret < 0) {
- dev_err(chip->dev, "rt1711 reg read fail\n");
- return ret;
- }
- return val;
-}
-
-static int rt1711_reg_write(struct i2c_client *i2c, u8 reg, const u8 data)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(i2c);
- int ret = 0;
-
-#ifdef CONFIG_RT_REGMAP
- ret = rt_regmap_block_write(chip->m_dev, reg, 1, &data);
-#else
- ret = rt1711_write_device(chip->client, reg, 1, &data);
-#endif /* CONFIG_RT_REGMAP */
- if (ret < 0)
- dev_err(chip->dev, "rt1711 reg write fail\n");
- return ret;
-}
-
-static int rt1711_block_read(struct i2c_client *i2c,
- u8 reg, int len, void *dst)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(i2c);
- int ret = 0;
-#ifdef CONFIG_RT_REGMAP
- ret = rt_regmap_block_read(chip->m_dev, reg, len, dst);
-#else
- ret = rt1711_read_device(chip->client, reg, len, dst);
-#endif /* #ifdef CONFIG_RT_REGMAP */
- if (ret < 0)
- dev_err(chip->dev, "rt1711 block read fail\n");
- return ret;
-}
-
-static int rt1711_block_write(struct i2c_client *i2c,
- u8 reg, int len, const void *src)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(i2c);
- int ret = 0;
-#ifdef CONFIG_RT_REGMAP
- ret = rt_regmap_block_write(chip->m_dev, reg, len, src);
-#else
- ret = rt1711_write_device(chip->client, reg, len, src);
-#endif /* #ifdef CONFIG_RT_REGMAP */
- if (ret < 0)
- dev_err(chip->dev, "rt1711 block write fail\n");
- return ret;
-}
-
-static int32_t rt1711_write_word(struct i2c_client *client,
- u8 reg_addr, u16 data)
-{
- int ret;
-
- /* don't need swap */
- ret = rt1711_block_write(client, reg_addr, 2, (u8 *)&data);
- return ret;
-}
-
-static int32_t rt1711_read_word(struct i2c_client *client,
- u8 reg_addr, u16 *data)
-{
- int ret;
-
- /* don't need swap */
- ret = rt1711_block_read(client, reg_addr, 2, (u8 *)data);
- return ret;
-}
-
-static inline int rt1711_i2c_write8(
- struct tcpc_device *tcpc, u8 reg, const u8 data)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
-
- return rt1711_reg_write(chip->client, reg, data);
-}
-
-static inline int rt1711_i2c_write16(
- struct tcpc_device *tcpc, u8 reg, const u16 data)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
-
- return rt1711_write_word(chip->client, reg, data);
-}
-
-static inline int rt1711_i2c_read8(struct tcpc_device *tcpc, u8 reg)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
-
- return rt1711_reg_read(chip->client, reg);
-}
-
-static inline int rt1711_i2c_read16(
- struct tcpc_device *tcpc, u8 reg)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
- u16 data;
- int ret;
-
- ret = rt1711_read_word(chip->client, reg, &data);
- if (ret < 0)
- return ret;
- return data;
-}
-
-#ifdef CONFIG_RT_REGMAP
-static struct rt_regmap_fops rt1711_regmap_fops = {
- .read_device = rt1711_read_device,
- .write_device = rt1711_write_device,
-};
-#endif /* CONFIG_RT_REGMAP */
-
-static int rt1711_regmap_init(struct rt1711_chip *chip)
-{
-#ifdef CONFIG_RT_REGMAP
- struct rt_regmap_properties *props;
- char name[32];
- int len;
-
- props = devm_kzalloc(chip->dev, sizeof(*props), GFP_KERNEL);
- if (!props)
- return -ENOMEM;
-
- props->register_num = RT1711_CHIP_REGMAP_SIZE;
- props->rm = rt1711_chip_regmap;
-
- props->rt_regmap_mode = RT_MULTI_BYTE | RT_CACHE_DISABLE |
- RT_IO_PASS_THROUGH | RT_DBG_GENERAL;
- snprintf(name, 32, "rt1711-%02x", chip->client->addr);
-
- len = strlen(name);
- props->name = kzalloc(len + 1, GFP_KERNEL);
- props->aliases = kzalloc(len + 1, GFP_KERNEL);
- strcpy((char *)props->name, name);
- strcpy((char *)props->aliases, name);
- props->io_log_en = 0;
-
- chip->m_dev = rt_regmap_device_register(props,
- &rt1711_regmap_fops, chip->dev, chip->client, chip);
- if (!chip->m_dev) {
- dev_err(chip->dev, "rt1711 chip rt_regmap register fail\n");
- return -EINVAL;
- }
-#endif
- return 0;
-}
-
-static int rt1711_regmap_deinit(struct rt1711_chip *chip)
-{
-#ifdef CONFIG_RT_REGMAP
- rt_regmap_device_unregister(chip->m_dev);
-#endif
- return 0;
-}
-
-static inline int rt1711_software_reset(struct tcpc_device *tcpc)
-{
- int ret = rt1711_i2c_write8(tcpc, RT1711H_REG_SWRESET, 1);
-
- if (ret < 0)
- return ret;
-
- mdelay(1);
- return 0;
-}
-
-static inline int rt1711_command(struct tcpc_device *tcpc, u8 cmd)
-{
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_COMMAND, cmd);
-}
-
-static int rt1711_init_alert_mask(struct tcpc_device *tcpc)
-{
- u16 mask;
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
-
- mask = TCPC_V10_REG_ALERT_CC_STATUS | TCPC_V10_REG_ALERT_POWER_STATUS;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- /* Need to handle RX overflow */
- mask |= TCPC_V10_REG_ALERT_TX_SUCCESS | TCPC_V10_REG_ALERT_TX_DISCARDED
- | TCPC_V10_REG_ALERT_TX_FAILED
- | TCPC_V10_REG_ALERT_RX_HARD_RST
- | TCPC_V10_REG_ALERT_RX_STATUS
- | TCPC_V10_REG_RX_OVERFLOW;
-#endif
-
- mask |= TCPC_REG_ALERT_FAULT;
-
- return rt1711_write_word(chip->client, TCPC_V10_REG_ALERT_MASK, mask);
-}
-
-static int rt1711_init_power_status_mask(struct tcpc_device *tcpc)
-{
- const u8 mask = TCPC_V10_REG_POWER_STATUS_VBUS_PRES;
-
- return rt1711_i2c_write8(tcpc,
- TCPC_V10_REG_POWER_STATUS_MASK, mask);
-}
-
-static int rt1711_init_fault_mask(struct tcpc_device *tcpc)
-{
- const u8 mask =
- TCPC_V10_REG_FAULT_STATUS_VCONN_OV |
- TCPC_V10_REG_FAULT_STATUS_VCONN_OC;
-
- return rt1711_i2c_write8(tcpc,
- TCPC_V10_REG_FAULT_STATUS_MASK, mask);
-}
-
-static int rt1711_init_rt_mask(struct tcpc_device *tcpc)
-{
- u8 rt_mask = 0;
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- rt_mask |= RT1711H_REG_M_VBUS_80;
-#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
-
-#ifdef CONFIG_TYPEC_CAP_RA_DETACH
- if (tcpc->tcpc_flags & TCPC_FLAGS_CHECK_RA_DETACHE)
- rt_mask |= RT1711H_REG_M_RA_DETACH;
-#endif /* CONFIG_TYPEC_CAP_RA_DETACH */
-
-#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
- if (tcpc->tcpc_flags & TCPC_FLAGS_LPM_WAKEUP_WATCHDOG)
- rt_mask |= RT1711H_REG_M_WAKEUP;
-#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
-
- return rt1711_i2c_write8(tcpc, RT1711H_REG_RT_MASK, rt_mask);
-}
-
-static inline void rt1711_poll_ctrl(struct rt1711_chip *chip)
-{
- cancel_delayed_work_sync(&chip->poll_work);
-
- if (atomic_read(&chip->poll_count) == 0) {
- atomic_inc(&chip->poll_count);
- cpu_idle_poll_ctrl(true);
- }
-
- schedule_delayed_work(
- &chip->poll_work, msecs_to_jiffies(40));
-}
-
-static void rt1711_irq_work_handler(struct kthread_work *work)
-{
- struct rt1711_chip *chip =
- container_of(work, struct rt1711_chip, irq_work);
- int regval = 0;
- int gpio_val;
-
- rt1711_poll_ctrl(chip);
- /* make sure I2C bus had resumed */
- down(&chip->suspend_lock);
- tcpci_lock_typec(chip->tcpc);
-
-#ifdef DEBUG_GPIO
- gpio_set_value(DEBUG_GPIO, 1);
-#endif
-
- do {
- regval = tcpci_alert(chip->tcpc);
- if (regval)
- break;
- gpio_val = gpio_get_value(chip->irq_gpio);
- } while (gpio_val == 0);
-
- tcpci_unlock_typec(chip->tcpc);
- up(&chip->suspend_lock);
-
-#ifdef DEBUG_GPIO
- gpio_set_value(DEBUG_GPIO, 1);
-#endif
-}
-
-static void rt1711_poll_work(struct work_struct *work)
-{
- struct rt1711_chip *chip = container_of(
- work, struct rt1711_chip, poll_work.work);
-
- if (atomic_dec_and_test(&chip->poll_count))
- cpu_idle_poll_ctrl(false);
-}
-
-static irqreturn_t rt1711_intr_handler(int irq, void *data)
-{
- struct rt1711_chip *chip = data;
-
-#ifdef DEBUG_GPIO
- gpio_set_value(DEBUG_GPIO, 0);
-#endif
- kthread_queue_work(&chip->irq_worker, &chip->irq_work);
- return IRQ_HANDLED;
-}
-
-static int rt1711_init_alert(struct tcpc_device *tcpc)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
- struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
- int ret;
- char *name;
- int len;
-
- /* Clear Alert Mask & Status */
- rt1711_write_word(chip->client, TCPC_V10_REG_ALERT_MASK, 0);
- rt1711_write_word(chip->client, TCPC_V10_REG_ALERT, 0xffff);
-
- len = strlen(chip->tcpc_desc->name);
- name = kzalloc(len + 5, GFP_KERNEL);
- sprintf(name, "%s-IRQ", chip->tcpc_desc->name);
-
- pr_info("%s name = %s\n", __func__, chip->tcpc_desc->name);
- pr_info("%s gpio # = %d\n", __func__, chip->irq_gpio);
-
- ret = gpio_request(chip->irq_gpio, name);
-#ifdef DEBUG_GPIO
- gpio_request(DEBUG_GPIO, "debug_latency_pin");
- gpio_direction_output(DEBUG_GPIO, 1);
-#endif
- if (ret < 0) {
- pr_err("Error: failed to request GPIO%d (ret = %d)\n",
- chip->irq_gpio, ret);
- return ret;
- }
- pr_info("GPIO requested...\n");
-
- ret = gpio_direction_input(chip->irq_gpio);
- if (ret < 0) {
- pr_err("Error: failed to set GPIO%d as input pin(ret = %d)\n",
- chip->irq_gpio, ret);
- return ret;
- }
-
- chip->irq = gpio_to_irq(chip->irq_gpio);
- pr_info("%s : IRQ number = %d\n", __func__, chip->irq);
-
- /*
- * ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
- * rt1711_intr_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- * name, chip);
- */
-
- if (ret < 0) {
- pr_err("Error: failed to request irq%d (gpio = %d, ret = %d)\n",
- chip->irq, chip->irq_gpio, ret);
- return ret;
- }
- pr_info("%s : irq initialized...\n", __func__);
-
- kthread_init_worker(&chip->irq_worker);
- chip->irq_worker_task = kthread_run(kthread_worker_fn,
- &chip->irq_worker, chip->tcpc_desc->name);
- if (IS_ERR(chip->irq_worker_task)) {
- pr_err("Error: Could not create tcpc task\n");
- return -EINVAL;
- }
-
- sched_setscheduler(chip->irq_worker_task, SCHED_FIFO, ¶m);
- kthread_init_work(&chip->irq_work, rt1711_irq_work_handler);
-
- pr_info("IRQF_NO_THREAD Test\r\n");
- ret = request_irq(
- chip->irq, rt1711_intr_handler,
- IRQF_TRIGGER_FALLING | IRQF_NO_THREAD |
- IRQF_NO_SUSPEND, name, chip);
-
- enable_irq_wake(chip->irq);
-
- return 0;
-}
-
-static inline int rt1711h_set_clock_gating(
- struct tcpc_device *tcpc_dev, bool en)
-{
- int ret = 0;
-
-#ifdef CONFIG_TCPC_CLOCK_GATING
- u8 clk2 = RT1711H_REG_CLK_DIV_600K_EN
- | RT1711H_REG_CLK_DIV_300K_EN | RT1711H_REG_CLK_CK_300K_EN;
-
- u8 clk3 = RT1711H_REG_CLK_DIV_2P4M_EN;
-
- if (!en) {
- clk2 |=
- RT1711H_REG_CLK_BCLK2_EN | RT1711H_REG_CLK_BCLK_EN;
- clk3 |=
- RT1711H_REG_CLK_CK_24M_EN | RT1711H_REG_CLK_PCLK_EN;
- }
-
- ret = rt1711_i2c_write8(tcpc_dev, RT1711H_REG_CLK_CTRL2, clk2);
- if (ret == 0)
- ret = rt1711_i2c_write8(tcpc_dev, RT1711H_REG_CLK_CTRL3, clk3);
-#endif /* CONFIG_TCPC_CLOCK_GATING */
-
- return ret;
-}
-
-static inline int rt1711h_init_cc_params(
- struct tcpc_device *tcpc, u8 cc_res)
-{
- int rv = 0;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-#ifdef CONFIG_USB_PD_SNK_DFT_NO_GOOD_CRC
- if (cc_res == TYPEC_CC_VOLT_SNK_DFT)
- rv = rt1711_i2c_write8(tcpc, RT1711H_REG_BMCIO_RXDZSEL, 0x81);
- else
- rv = rt1711_i2c_write8(tcpc, RT1711H_REG_BMCIO_RXDZSEL, 0x80);
-#endif /* CONFIG_USB_PD_SNK_DFT_NO_GOOD_CRC */
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- return rv;
-}
-
-static int rt1711_tcpc_init(struct tcpc_device *tcpc, bool sw_reset)
-{
- int ret;
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
-
- RT1711_INFO("\n");
-
- if (sw_reset) {
- ret = rt1711_software_reset(tcpc);
- if (ret < 0)
- return ret;
- }
-
- /* CK_300K from 320K, SHIPPING off, AUTOIDLE enable, TIMEOUT = 32ms */
- rt1711_i2c_write8(
- tcpc, RT1711H_REG_IDLE_CTRL,
- RT1711H_REG_IDLE_SET(0, 1, 1, 2));
-
- /* UFP Both RD setting */
- /* DRP = 0, RpVal = 0 (Default), Rd, Rd */
- rt1711_i2c_write8(
- tcpc, TCPC_V10_REG_ROLE_CTRL,
- TCPC_V10_REG_ROLE_CTRL_RES_SET(0, 0, CC_RD, CC_RD));
-
- if (chip->chip_id == RT1711H_DID_A) {
- rt1711_i2c_write8(
- tcpc, TCPC_V10_REG_FAULT_CTRL,
- TCPC_V10_REG_FAULT_CTRL_DIS_VCONN_OV);
- }
-
- /*
- * CC Detect Debounce : 26.7*val us
- * Transition window count : spec 12~20us, based on 2.4MHz
- * DRP Toggle Cycle : 51.2 + 6.4*val ms
- * DRP Duyt Ctrl : dcSRC: /1024
- */
-
- rt1711_i2c_write8(tcpc, RT1711H_REG_TTCPC_FILTER, 5);
- rt1711_i2c_write8(tcpc, RT1711H_REG_DRP_TOGGLE_CYCLE, 4);
- rt1711_i2c_write16(tcpc, RT1711H_REG_DRP_DUTY_CTRL, 400);
-
- /* Vconn OC */
- rt1711_i2c_write8(tcpc, RT1711H_REG_VCONN_CLIMITEN, 1);
-
- /* RX/TX Clock Gating (Auto Mode)*/
- if (!sw_reset)
- rt1711h_set_clock_gating(tcpc, true);
-
- tcpci_alert_status_clear(tcpc, 0xffffffff);
-
- rt1711_init_power_status_mask(tcpc);
- rt1711_init_alert_mask(tcpc);
- rt1711_init_fault_mask(tcpc);
- rt1711_init_rt_mask(tcpc);
-
- return 0;
-}
-
-int rt1711_alert_status_clear(struct tcpc_device *tcpc, u32 mask)
-{
- int ret;
- u16 mask_t1;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- u8 mask_t2;
-#endif
-
- /* Write 1 clear */
- mask_t1 = (u16)mask;
- ret = rt1711_i2c_write16(tcpc, TCPC_V10_REG_ALERT, mask_t1);
- if (ret < 0)
- return ret;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- mask_t2 = mask >> 16;
- ret = rt1711_i2c_write8(tcpc, RT1711H_REG_RT_INT, mask_t2);
- if (ret < 0)
- return ret;
-#endif
-
- return 0;
-}
-
-int rt1711_fault_status_clear(struct tcpc_device *tcpc, u8 status)
-{
- /* Write 1 clear (Check it later )*/
- int ret;
-
- rt1711_i2c_write8(tcpc, TCPC_V10_REG_FAULT_STATUS, status);
-
- /* discharge ... */
- ret = rt1711_i2c_read8(tcpc, RT1711H_REG_BMC_CTRL);
- if (ret < 0)
- return ret;
-
- rt1711_i2c_write8(
- tcpc, RT1711H_REG_BMC_CTRL,
- ret & (~RT1711H_REG_DISCHARGE_EN));
-
- return 0;
-}
-
-int rt1711_get_alert_status(struct tcpc_device *tcpc, u32 *alert)
-{
- int ret;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- u8 v2;
-#endif
-
- ret = rt1711_i2c_read16(tcpc, TCPC_V10_REG_ALERT);
- if (ret < 0)
- return ret;
-
- *alert = (u16)ret;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- ret = rt1711_i2c_read8(tcpc, RT1711H_REG_RT_INT);
- if (ret < 0)
- return ret;
-
- v2 = (u8)ret;
- *alert |= v2 << 16;
-#endif
-
- return 0;
-}
-
-static int rt1711_get_power_status(
- struct tcpc_device *tcpc, u16 *pwr_status)
-{
- int ret;
-
- ret = rt1711_i2c_read8(tcpc, TCPC_V10_REG_POWER_STATUS);
- if (ret < 0)
- return ret;
-
- *pwr_status = 0;
-
- if (ret & TCPC_V10_REG_POWER_STATUS_VBUS_PRES)
- *pwr_status |= TCPC_REG_POWER_STATUS_VBUS_PRES;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- ret = rt1711_i2c_read8(tcpc, RT1711H_REG_RT_STATUS);
- if (ret < 0)
- return ret;
-
- if (ret & RT1711H_REG_VBUS_80)
- *pwr_status |= TCPC_REG_POWER_STATUS_EXT_VSAFE0V;
-#endif
- return 0;
-}
-
-int rt1711_get_fault_status(struct tcpc_device *tcpc, u8 *status)
-{
- int ret;
-
- ret = rt1711_i2c_read8(tcpc, TCPC_V10_REG_FAULT_STATUS);
- if (ret < 0)
- return ret;
- *status = (u8)ret;
- return 0;
-}
-
-static int rt1711_get_cc(struct tcpc_device *tcpc, int *cc1, int *cc2)
-{
- int status, role_ctrl, cc_role;
- bool act_as_sink, act_as_drp;
-
- status = rt1711_i2c_read8(tcpc, TCPC_V10_REG_CC_STATUS);
- if (status < 0)
- return status;
-
- role_ctrl = rt1711_i2c_read8(tcpc, TCPC_V10_REG_ROLE_CTRL);
- if (role_ctrl < 0)
- return role_ctrl;
-
- if (status & TCPC_V10_REG_CC_STATUS_DRP_TOGGLING) {
- *cc1 = TYPEC_CC_DRP_TOGGLING;
- *cc2 = TYPEC_CC_DRP_TOGGLING;
- return 0;
- }
-
- *cc1 = TCPC_V10_REG_CC_STATUS_CC1(status);
- *cc2 = TCPC_V10_REG_CC_STATUS_CC2(status);
-
- act_as_drp = TCPC_V10_REG_ROLE_CTRL_DRP & role_ctrl;
-
- if (act_as_drp) {
- act_as_sink = TCPC_V10_REG_CC_STATUS_DRP_RESULT(status);
- } else {
- cc_role = TCPC_V10_REG_CC_STATUS_CC1(role_ctrl);
- if (cc_role == TYPEC_CC_RP)
- act_as_sink = false;
- else
- act_as_sink = true;
- }
-
- /*
- * If status is not open, then OR in termination to convert to
- * enum tcpc_cc_voltage_status.
- */
-
- if (*cc1 != TYPEC_CC_VOLT_OPEN)
- *cc1 |= (act_as_sink << 2);
-
- if (*cc2 != TYPEC_CC_VOLT_OPEN)
- *cc2 |= (act_as_sink << 2);
-
- rt1711h_init_cc_params(
- tcpc,
- (u8)tcpc->typec_polarity ? *cc2 : *cc1);
-
- return 0;
-}
-
-static int rt1711_set_cc(struct tcpc_device *tcpc, int pull)
-{
- int ret;
- u8 data;
- int rp_lvl = TYPEC_CC_PULL_GET_RP_LVL(pull);
-
- RT1711_INFO("\n");
- pull = TYPEC_CC_PULL_GET_RES(pull);
- if (pull == TYPEC_CC_DRP) {
- data = TCPC_V10_REG_ROLE_CTRL_RES_SET(
- 1, rp_lvl, TYPEC_CC_RD, TYPEC_CC_RD);
-
- ret = rt1711_i2c_write8(
- tcpc, TCPC_V10_REG_ROLE_CTRL, data);
-
- if (ret == 0)
- ret = rt1711_command(tcpc, TCPM_CMD_LOOK_CONNECTION);
- } else {
- data = TCPC_V10_REG_ROLE_CTRL_RES_SET(0, rp_lvl, pull, pull);
- ret = rt1711_i2c_write8(tcpc, TCPC_V10_REG_ROLE_CTRL, data);
- }
-
- return 0;
-}
-
-static int rt1711_set_polarity(struct tcpc_device *tcpc, int polarity)
-{
- int data;
-
- data = rt1711h_init_cc_params(tcpc,
- tcpc->typec_remote_cc[polarity]);
- if (data)
- return data;
-
- data = rt1711_i2c_read8(tcpc, TCPC_V10_REG_TCPC_CTRL);
- if (data < 0)
- return data;
-
- data &= ~TCPC_V10_REG_TCPC_CTRL_PLUG_ORIENT;
- data |= polarity ? TCPC_V10_REG_TCPC_CTRL_PLUG_ORIENT : 0;
-
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_TCPC_CTRL, data);
-}
-
-static int rt1711_set_vconn(struct tcpc_device *tcpc, int enable)
-{
- int data;
-
- data = rt1711_i2c_read8(tcpc, TCPC_V10_REG_POWER_CTRL);
- if (data < 0)
- return data;
-
- data &= ~TCPC_V10_REG_POWER_CTRL_VCONN;
- data |= enable ? TCPC_V10_REG_POWER_CTRL_VCONN : 0;
-
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_POWER_CTRL, data);
-}
-
-#ifdef CONFIG_TCPC_LOW_POWER_MODE
-static int rt1711_set_low_power_mode(
- struct tcpc_device *tcpc_dev, bool en, int pull)
-{
- int rv = 0;
- u8 data;
-
- if (en) {
- data = RT1711H_REG_BMCIO_LPEN;
-
- if (pull & TYPEC_CC_RP)
- data |= RT1711H_REG_BMCIO_LPRPRD;
- } else {
- data = RT1711H_REG_BMCIO_BG_EN |
- RT1711H_REG_VBUS_DET_EN | RT1711H_REG_BMCIO_OSC_EN;
- }
- rv = rt1711_i2c_write8(tcpc_dev, RT1711H_REG_BMC_CTRL, data);
- return rv;
-}
-#endif /* CONFIG_TCPC_LOW_POWER_MODE */
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-static int rt1711_set_msg_header(
- struct tcpc_device *tcpc, int power_role, int data_role)
-{
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_MSG_HDR_INFO,
- TCPC_V10_REG_MSG_HDR_INFO_SET(data_role, power_role));
-}
-
-static int rt1711_set_rx_enable(struct tcpc_device *tcpc, u8 enable)
-{
- int ret = rt1711h_set_clock_gating(tcpc, !enable);
-
- if (ret == 0)
- ret = rt1711_i2c_write8(tcpc, TCPC_V10_REG_RX_DETECT, enable);
- return ret;
-}
-
-static int rt1711_get_message(
- struct tcpc_device *tcpc, u32 *payload,
- u16 *msg_head, enum tcpm_transmit_type *frame_type)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
- int rv;
- u8 type, cnt = 0;
- u8 buf[4];
- const u16 alert_rx =
- TCPC_V10_REG_ALERT_RX_STATUS | TCPC_V10_REG_RX_OVERFLOW;
-
- rv = rt1711_block_read(chip->client,
- TCPC_V10_REG_RX_BYTE_CNT, 4, buf);
- cnt = buf[0];
- type = buf[1];
- *msg_head = *(u16 *)&buf[2];
-
- /* TCPC 1.0 ==> no need to subtract the size of msg_head */
- if (rv >= 0 && cnt > 0) {
- cnt -= 3; /* MSG_HDR */
- rv = rt1711_block_read(
- chip->client, TCPC_V10_REG_RX_DATA, cnt,
- (u8 *)payload);
- }
-
- *frame_type = (enum tcpm_transmit_type)type;
-
- /* Read complete, clear RX status alert bit */
- tcpci_alert_status_clear(tcpc, alert_rx);
-
- /*mdelay(1); */
- return rv;
-}
-
-static int rt1711_set_bist_carrier_mode(
- struct tcpc_device *tcpc, u8 pattern)
-{
- /* Don't support this function */
- return 0;
-}
-
-/* message header (2byte) + data object (7*4) */
-#define RT1711_TRANSMIT_MAX_SIZE (sizeof(u16) + sizeof(u32) * 7)
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
-static int rt1711_retransmit(struct tcpc_device *tcpc)
-{
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_TRANSMIT,
- TCPC_V10_REG_TRANSMIT_SET(TCPC_TX_SOP));
-}
-#endif
-
-static int rt1711_transmit(struct tcpc_device *tcpc,
- enum tcpm_transmit_type type,
- u16 header, const u32 *data)
-{
- struct rt1711_chip *chip = tcpc_get_dev_data(tcpc);
- int rv;
- int data_cnt, packet_cnt;
- u8 temp[RT1711_TRANSMIT_MAX_SIZE];
-
- if (type < TCPC_TX_HARD_RESET) {
- data_cnt = sizeof(u32) * PD_HEADER_CNT(header);
- packet_cnt = data_cnt + sizeof(u16);
-
- temp[0] = packet_cnt;
- memcpy(temp + 1, (u8 *)&header, 2);
- if (data_cnt > 0)
- memcpy(temp + 3, (u8 *)data, data_cnt);
-
- rv = rt1711_block_write(
- chip->client,
- TCPC_V10_REG_TX_BYTE_CNT,
- packet_cnt + 1, (u8 *)temp);
- if (rv < 0)
- return rv;
- }
-
- rv = rt1711_i2c_write8(
- tcpc, TCPC_V10_REG_TRANSMIT,
- TCPC_V10_REG_TRANSMIT_SET(type));
- return rv;
-}
-
-static int rt1711_set_bist_test_mode(struct tcpc_device *tcpc, bool en)
-{
- int data;
-
- data = rt1711_i2c_read8(tcpc, TCPC_V10_REG_TCPC_CTRL);
- if (data < 0)
- return data;
-
- data &= ~TCPC_V10_REG_TCPC_CTRL_BIST_TEST_MODE;
- data |= en ? TCPC_V10_REG_TCPC_CTRL_BIST_TEST_MODE : 0;
-
- return rt1711_i2c_write8(tcpc, TCPC_V10_REG_TCPC_CTRL, data);
-}
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-static struct tcpc_ops rt1711_tcpc_ops = {
- .init = rt1711_tcpc_init,
- .alert_status_clear = rt1711_alert_status_clear,
- .fault_status_clear = rt1711_fault_status_clear,
- .get_alert_status = rt1711_get_alert_status,
- .get_power_status = rt1711_get_power_status,
- .get_fault_status = rt1711_get_fault_status,
- .get_cc = rt1711_get_cc,
- .set_cc = rt1711_set_cc,
- .set_polarity = rt1711_set_polarity,
- .set_vconn = rt1711_set_vconn,
-
-#ifdef CONFIG_TCPC_LOW_POWER_MODE
- .set_low_power_mode = rt1711_set_low_power_mode,
-#endif
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- .set_msg_header = rt1711_set_msg_header,
- .set_rx_enable = rt1711_set_rx_enable,
- .get_message = rt1711_get_message,
- .transmit = rt1711_transmit,
- .set_bist_test_mode = rt1711_set_bist_test_mode,
- .set_bist_carrier_mode = rt1711_set_bist_carrier_mode,
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- .retransmit = rt1711_retransmit,
-#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
-
-};
-
-static int rt_parse_dt(struct rt1711_chip *chip, struct device *dev)
-{
- struct device_node *np = dev->of_node;
-
- if (!np)
- return -EINVAL;
-
- pr_info("%s\n", __func__);
- chip->irq_gpio = of_get_named_gpio(np, "rt1711,irq_pin", 0);
-
- return 0;
-}
-
-static int rt1711_tcpcdev_init(struct rt1711_chip *chip, struct device *dev)
-{
- struct tcpc_desc *desc;
- struct device_node *np = dev->of_node;
- u32 val, len;
- const char *name = "default";
-
- desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
- if (of_property_read_u32(np, "rt-tcpc,role_def", &val) >= 0) {
- if (val >= TYPEC_ROLE_NR)
- desc->role_def = TYPEC_ROLE_DRP;
- else
- desc->role_def = val;
- } else {
- dev_info(dev, "use default Role DRP\n");
- desc->role_def = TYPEC_ROLE_DRP;
- }
-
- if (of_property_read_u32(
- np, "rt-tcpc,notifier_supply_num", &val) >= 0) {
- if (val < 0)
- desc->notifier_supply_num = 0;
- else
- desc->notifier_supply_num = val;
- } else {
- desc->notifier_supply_num = 0;
- }
- if (of_property_read_u32(np, "rt-tcpc,rp_level", &val) >= 0) {
- switch (val) {
- case 0: /* RP Default */
- desc->rp_lvl = TYPEC_CC_RP_DFT;
- break;
- case 1: /* RP 1.5V */
- desc->rp_lvl = TYPEC_CC_RP_1_5;
- break;
- case 2: /* RP 3.0V */
- desc->rp_lvl = TYPEC_CC_RP_3_0;
- break;
- default:
- break;
- }
- }
- of_property_read_string(np, "rt-tcpc,name", (char const **)&name);
-
- len = strlen(name);
- desc->name = kzalloc(len + 1, GFP_KERNEL);
- strcpy((char *)desc->name, name);
-
- chip->tcpc_desc = desc;
-
- chip->tcpc = tcpc_device_register(dev,
- desc, &rt1711_tcpc_ops, chip);
- if (IS_ERR(chip->tcpc))
- return -EINVAL;
-
- if (chip->chip_id <= RT1711H_DID_B) {
- chip->tcpc->tcpc_flags =
- TCPC_FLAGS_RETRY_CRC_DISCARD |
- TCPC_FLAGS_WAIT_HRESET_COMPLETE |
- TCPC_FLAGS_LPM_WAKEUP_WATCHDOG;
- } else {
- chip->tcpc->tcpc_flags =
- TCPC_FLAGS_RETRY_CRC_DISCARD |
- TCPC_FLAGS_WAIT_HRESET_COMPLETE |
- TCPC_FLAGS_CHECK_RA_DETACHE;
- }
- return 0;
-}
-
-#define RICHTEK_1711_VID 0x29cf
-#define RICHTEK_1711_PID 0x1711
-
-static inline int rt1711h_check_revision(struct i2c_client *client)
-{
- u16 vid, pid, did;
- int ret;
- u8 data = 1;
-
- ret = rt1711_read_device(client, TCPC_V10_REG_VID, 2, &vid);
- if (ret < 0) {
- dev_err(&client->dev, "read chip ID fail\n");
- return -EIO;
- }
-
- if (vid != RICHTEK_1711_VID) {
- pr_info("%s failed, VID=0x%04x\n", __func__, vid);
- return -ENODEV;
- }
-
- ret = rt1711_read_device(client, TCPC_V10_REG_PID, 2, &pid);
- if (ret < 0) {
- dev_err(&client->dev, "read product ID fail\n");
- return -EIO;
- }
-
- if (pid != RICHTEK_1711_PID) {
- pr_info("%s failed, PID=0x%04x\n", __func__, pid);
- return -ENODEV;
- }
-
- ret = rt1711_write_device(client, RT1711H_REG_SWRESET, 1, &data);
- if (ret < 0)
- return ret;
-
- mdelay(1);
-
- ret = rt1711_read_device(client, TCPC_V10_REG_DID, 2, &did);
- if (ret < 0) {
- dev_err(&client->dev, "read device ID fail\n");
- return -EIO;
- }
-
- return did;
-}
-
-static int rt1711_i2c_probe(
- struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct rt1711_chip *chip;
- int ret = 0, chip_id;
- bool use_dt = client->dev.of_node;
-
- pr_info("%s\n", __func__);
-
- if (i2c_check_functionality(
- client->adapter,
- I2C_FUNC_SMBUS_I2C_BLOCK |
- I2C_FUNC_SMBUS_BYTE_DATA))
- pr_info("I2C functionality : OK...\n");
- else
- pr_info("I2C functionality check : failuare...\n");
-
- chip_id = rt1711h_check_revision(client);
- if (chip_id < 0)
- return ret;
-
- chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- if (use_dt) {
- rt_parse_dt(chip, &client->dev);
- } else {
- dev_err(&client->dev, "no dts node\n");
- return -ENODEV;
- }
- chip->dev = &client->dev;
- chip->client = client;
- sema_init(&chip->io_lock, 1);
- sema_init(&chip->suspend_lock, 1);
- i2c_set_clientdata(client, chip);
- INIT_DELAYED_WORK(&chip->poll_work, rt1711_poll_work);
-
- chip->chip_id = chip_id;
- pr_info("rt1711h_chipID = 0x%0x\n", chip_id);
-
- ret = rt1711_regmap_init(chip);
- if (ret < 0) {
- dev_err(chip->dev, "rt1711 regmap init fail\n");
- return -EINVAL;
- }
-
- ret = rt1711_tcpcdev_init(chip, &client->dev);
- if (ret < 0) {
- dev_err(&client->dev, "rt1711 tcpc dev init fail\n");
- goto err_tcpc_reg;
- }
-
- ret = rt1711_init_alert(chip->tcpc);
- if (ret < 0) {
- pr_err("rt1711 init alert fail\n");
- goto err_irq_init;
- }
-
- tcpc_schedule_init_work(chip->tcpc);
-
- pr_info("%s probe OK!\n", __func__);
- return 0;
-
-err_irq_init:
- tcpc_device_unregister(chip->dev, chip->tcpc);
-err_tcpc_reg:
- rt1711_regmap_deinit(chip);
- return ret;
-}
-
-static int rt1711_i2c_remove(struct i2c_client *client)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(client);
-
- if (chip) {
- cancel_delayed_work_sync(&chip->poll_work);
-
- tcpc_device_unregister(chip->dev, chip->tcpc);
- rt1711_regmap_deinit(chip);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int rt1711_i2c_suspend(struct device *dev)
-{
- struct rt1711_chip *chip;
- struct i2c_client *client = to_i2c_client(dev);
-
- if (client) {
- chip = i2c_get_clientdata(client);
- if (chip)
- down(&chip->suspend_lock);
- }
-
- return 0;
-}
-
-static int rt1711_i2c_resume(struct device *dev)
-{
- struct rt1711_chip *chip;
- struct i2c_client *client = to_i2c_client(dev);
-
- if (client) {
- chip = i2c_get_clientdata(client);
- if (chip)
- up(&chip->suspend_lock);
- }
-
- return 0;
-}
-
-static void rt1711_shutdown(struct i2c_client *client)
-{
- struct rt1711_chip *chip = i2c_get_clientdata(client);
-
- /* Please reset IC here */
- if (chip && chip->irq)
- disable_irq(chip->irq);
- i2c_smbus_write_byte_data(client, RT1711H_REG_SWRESET, 0x01);
-}
-
-static int rt1711_pm_suspend_runtime(struct device *device)
-{
- dev_dbg(device, "pm_runtime: suspending...\n");
- return 0;
-}
-
-static int rt1711_pm_resume_runtime(struct device *device)
-{
- dev_dbg(device, "pm_runtime: resuming...\n");
- return 0;
-}
-
-static const struct dev_pm_ops rt1711_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(
- rt1711_i2c_suspend,
- rt1711_i2c_resume)
- SET_RUNTIME_PM_OPS(
- rt1711_pm_suspend_runtime,
- rt1711_pm_resume_runtime,
- NULL
- )
-};
-
-#define RT1711_PM_OPS (&rt1711_pm_ops)
-#else
-#define RT1711_PM_OPS (NULL)
-#endif /* CONFIG_PM */
-
-static const struct i2c_device_id rt1711_id_table[] = {
- {"rt1711", 0},
- {},
-};
-MODULE_DEVICE_TABLE(i2c, rt1711_id_table);
-
-static const struct of_device_id rt_match_table[] = {
- {.compatible = "richtek,rt1711",},
- {},
-};
-
-static struct i2c_driver rt1711_driver = {
- .driver = {
- .name = "rt1711h",
- .owner = THIS_MODULE,
- .of_match_table = rt_match_table,
- .pm = RT1711_PM_OPS,
- },
- .probe = rt1711_i2c_probe,
- .remove = rt1711_i2c_remove,
- .shutdown = rt1711_shutdown,
- .id_table = rt1711_id_table,
-};
-
-static int __init rt1711_init(void)
-{
- struct device_node *np;
-
- pr_info("rt1711h_init (%s): initializing...\n", RT1711H_DRV_VERSION);
- np = of_find_node_by_name(NULL, "rt1711");
- if (np)
- pr_info("rt1711h node found...\n");
- else
- pr_info("rt1711h node not found...\n");
-
- return i2c_add_driver(&rt1711_driver);
-}
-module_init(rt1711_init);
-
-static void __exit rt1711_exit(void)
-{
- i2c_del_driver(&rt1711_driver);
-}
-module_exit(rt1711_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
-MODULE_DESCRIPTION("RT1711 TCPC Driver");
-MODULE_VERSION(RT1711H_DRV_VERSION);
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * TCPC Interface for alert handler
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/cpu.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-static int tcpci_alert_cc_changed(struct tcpc_device *tcpc_dev)
-{
- return tcpc_typec_handle_cc_change(tcpc_dev);
-}
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
-
-static inline int tcpci_alert_vsafe0v(struct tcpc_device *tcpc_dev)
-{
- tcpc_typec_handle_vsafe0v(tcpc_dev);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- pd_put_vbus_safe0v_event(tcpc_dev);
-#endif
-
- return 0;
-}
-
-#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
-
-void tcpci_vbus_level_init(struct tcpc_device *tcpc_dev, u16 power_status)
-{
- mutex_lock(&tcpc_dev->access_lock);
-
- tcpc_dev->vbus_level =
- power_status & TCPC_REG_POWER_STATUS_VBUS_PRES ?
- TCPC_VBUS_VALID : TCPC_VBUS_INVALID;
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- if (power_status & TCPC_REG_POWER_STATUS_EXT_VSAFE0V) {
- if (tcpc_dev->vbus_level == TCPC_VBUS_INVALID)
- tcpc_dev->vbus_level = TCPC_VBUS_SAFE0V;
- else
- TCPC_INFO("ps_confused: 0x%02x\r\n", power_status);
- }
-#endif
-
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-static int tcpci_alert_power_status_changed(struct tcpc_device *tcpc_dev)
-{
- int rv = 0;
- u16 power_status = 0;
-
- rv = tcpci_get_power_status(tcpc_dev, &power_status);
- if (rv < 0)
- return rv;
-
- tcpci_vbus_level_init(tcpc_dev, power_status);
-
- TCPC_INFO("ps_change=%d\r\n", tcpc_dev->vbus_level);
- rv = tcpc_typec_handle_ps_change(
- tcpc_dev,
- tcpc_dev->vbus_level == TCPC_VBUS_VALID);
- if (rv < 0)
- return rv;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- pd_put_vbus_changed_event(tcpc_dev, true);
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT_IC
- if (tcpc_dev->vbus_level == TCPC_VBUS_SAFE0V)
- rv = tcpci_alert_vsafe0v(tcpc_dev);
-#endif /* CONFIG_TCPC_VSAFE0V_DETECT_IC */
-
- return rv;
-}
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-static int tcpci_alert_tx_success(struct tcpc_device *tcpc_dev)
-{
- u8 tx_state;
-
- pd_event_t evt = {
- .event_type = PD_EVT_CTRL_MSG,
- .msg = PD_CTRL_GOOD_CRC,
- .pd_msg = NULL,
- };
-
- mutex_lock(&tcpc_dev->access_lock);
- tx_state = tcpc_dev->pd_transmit_state;
- tcpc_dev->pd_transmit_state = PD_TX_STATE_GOOD_CRC;
- mutex_unlock(&tcpc_dev->access_lock);
-
- if (tx_state == PD_TX_STATE_WAIT_CRC_VDM)
- pd_put_vdm_event(tcpc_dev, &evt, false);
- else
- pd_put_event(tcpc_dev, &evt, false);
-
- return 0;
-}
-
-static int tcpci_alert_tx_failed(struct tcpc_device *tcpc_dev)
-{
- u8 tx_state;
-
- mutex_lock(&tcpc_dev->access_lock);
- tx_state = tcpc_dev->pd_transmit_state;
- tcpc_dev->pd_transmit_state = PD_TX_STATE_NO_GOOD_CRC;
- mutex_unlock(&tcpc_dev->access_lock);
-
- if (tx_state == PD_TX_STATE_WAIT_CRC_VDM)
- vdm_put_hw_event(tcpc_dev, PD_HW_TX_FAILED);
- else
- pd_put_hw_event(tcpc_dev, PD_HW_TX_FAILED);
-
- return 0;
-}
-
-static int tcpci_alert_tx_discard(struct tcpc_device *tcpc_dev)
-{
- u8 tx_state;
- bool retry_crc_discard = false;
-
- mutex_lock(&tcpc_dev->access_lock);
- tx_state = tcpc_dev->pd_transmit_state;
- tcpc_dev->pd_transmit_state = PD_TX_STATE_DISCARD;
- mutex_unlock(&tcpc_dev->access_lock);
-
- TCPC_INFO("Discard\r\n");
-
- if (tx_state == PD_TX_STATE_WAIT_CRC_VDM) {
- pd_put_last_vdm_event(tcpc_dev);
- } else {
- retry_crc_discard =
- (tcpc_dev->tcpc_flags &
- TCPC_FLAGS_RETRY_CRC_DISCARD) != 0;
-
- if (retry_crc_discard) {
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- tcpc_dev->pd_discard_pending = true;
- tcpc_enable_timer(tcpc_dev, PD_TIMER_DISCARD);
-#else
- TCPC_ERR("RETRY_CRC_DISCARD\r\n");
-#endif
- } else {
- pd_put_hw_event(tcpc_dev, PD_HW_TX_FAILED);
- }
- }
- return 0;
-}
-
-static int tcpci_alert_recv_msg(struct tcpc_device *tcpc_dev)
-{
- int retval;
- pd_msg_t *pd_msg;
- enum tcpm_transmit_type type;
-
- pd_msg = pd_alloc_msg(tcpc_dev);
- if (!pd_msg)
- return -1; /* TODO */
-
- retval = tcpci_get_message(tcpc_dev,
- pd_msg->payload, &pd_msg->msg_hdr, &type);
- if (retval < 0) {
- TCPC_INFO("recv_msg failed: %d\r\n", retval);
- pd_free_msg(tcpc_dev, pd_msg);
- return retval;
- }
-
- pd_msg->frame_type = (u8)type;
- pd_put_pd_msg_event(tcpc_dev, pd_msg);
- return 0;
-}
-
-static int tcpci_alert_rx_overflow(struct tcpc_device *tcpc_dev)
-{
- TCPC_INFO("RX_OVERFLOW\r\n");
- return 0;
-}
-
-static int tcpci_alert_fault(struct tcpc_device *tcpc_dev)
-{
- u8 status = 0;
-
- tcpci_get_fault_status(tcpc_dev, &status);
- TCPC_INFO("FaultAlert=0x%x\r\n", status);
- tcpci_fault_status_clear(tcpc_dev, status);
- return 0;
-}
-
-static int tcpci_alert_recv_hard_reset(struct tcpc_device *tcpc_dev)
-{
- TCPC_INFO("HardResetAlert\r\n");
- pd_put_recv_hard_reset_event(tcpc_dev);
- return 0;
-}
-
-#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
-static int tcpci_alert_wakeup(struct tcpc_device *tcpc_dev)
-{
- if (tcpc_dev->tcpc_flags & TCPC_FLAGS_LPM_WAKEUP_WATCHDOG) {
- TCPC_DBG("Wakeup\r\n");
-
- if (tcpc_dev->typec_remote_cc[0] == TYPEC_CC_DRP_TOGGLING &&
- tcpc_dev->typec_remote_cc[1] == TYPEC_CC_DRP_TOGGLING)
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_WAKEUP);
- }
-
- return 0;
-}
-#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
-
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-typedef struct __tcpci_alert_handler {
- u32 bit_mask;
- int (*handler)(struct tcpc_device *tcpc_dev);
-} tcpci_alert_handler_t;
-
-#define DECL_TCPCI_ALERT_HANDLER(xbit, xhandler) {\
- .bit_mask = 1 << (xbit),\
- .handler = xhandler, \
- }
-
-const tcpci_alert_handler_t tcpci_alert_handlers[] = {
-#ifdef CONFIG_USB_POWER_DELIVERY
- DECL_TCPCI_ALERT_HANDLER(4, tcpci_alert_tx_failed),
- DECL_TCPCI_ALERT_HANDLER(5, tcpci_alert_tx_discard),
- DECL_TCPCI_ALERT_HANDLER(6, tcpci_alert_tx_success),
- DECL_TCPCI_ALERT_HANDLER(2, tcpci_alert_recv_msg),
- DECL_TCPCI_ALERT_HANDLER(7, NULL),
- DECL_TCPCI_ALERT_HANDLER(8, NULL),
- DECL_TCPCI_ALERT_HANDLER(3, tcpci_alert_recv_hard_reset),
- DECL_TCPCI_ALERT_HANDLER(10, tcpci_alert_rx_overflow),
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
- DECL_TCPCI_ALERT_HANDLER(16, tcpci_alert_wakeup),
-#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
- DECL_TCPCI_ALERT_HANDLER(9, tcpci_alert_fault),
- DECL_TCPCI_ALERT_HANDLER(0, tcpci_alert_cc_changed),
- DECL_TCPCI_ALERT_HANDLER(1, tcpci_alert_power_status_changed),
-};
-
-static inline int __tcpci_alert(struct tcpc_device *tcpc_dev)
-{
- int rv, i;
- u32 alert_status;
- const u32 alert_rx =
- TCPC_REG_ALERT_RX_STATUS | TCPC_REG_ALERT_RX_BUF_OVF;
-
- const u32 alert_sent_hreset =
- TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED;
-
- rv = tcpci_get_alert_status(tcpc_dev, &alert_status);
- if (rv)
- return rv;
-
- tcpci_alert_status_clear(tcpc_dev, alert_status & (~alert_rx));
-
- if (tcpc_dev->typec_role == TYPEC_ROLE_UNKNOWN) {
- TCPC_INFO("SkipAlert:0x%04x\r\n", alert_status);
- return 0;
- }
-
- if (alert_status & TCPC_REG_ALERT_EXT_VBUS_80)
- alert_status |= TCPC_REG_ALERT_POWER_STATUS;
-
-#ifdef CONFIG_TYPEC_CAP_RA_DETACH
- if ((alert_status & TCPC_REG_ALERT_EXT_RA_DETACH) &&
- (tcpc_dev->tcpc_flags & TCPC_FLAGS_CHECK_RA_DETACHE))
- alert_status |= TCPC_REG_ALERT_CC_STATUS;
-#endif /* CONFIG_TYPEC_CAP_RA_DETACH */
-
-#ifdef CONFIG_USB_PD_IGNORE_HRESET_COMPLETE_TIMER
- if ((alert_status & alert_sent_hreset) == alert_sent_hreset) {
- if (tcpc_dev->tcpc_flags & TCPC_FLAGS_WAIT_HRESET_COMPLETE) {
- alert_status &= ~alert_sent_hreset;
- pd_put_sent_hard_reset_event(tcpc_dev);
- }
- }
-#endif /* CONFIG_USB_PD_IGNORE_HRESET_COMPLETE_TIMER */
-
- for (i = 0; i < ARRAY_SIZE(tcpci_alert_handlers); i++) {
- if (tcpci_alert_handlers[i].bit_mask & alert_status) {
- if (tcpci_alert_handlers[i].handler != 0)
- tcpci_alert_handlers[i].handler(tcpc_dev);
- }
- }
- return 0;
-}
-
-int tcpci_alert(struct tcpc_device *tcpc_dev)
-{
- int ret;
-
- ret = __tcpci_alert(tcpc_dev);
-
- return ret;
-}
-EXPORT_SYMBOL(tcpci_alert);
-
-/*
- * [BLOCK] TYPEC device changed
- */
-
-static inline int tcpci_report_usb_port_attached(struct tcpc_device *tcpc)
-{
- TCPC_INFO("usb_port_attached\r\n");
-
- __pm_relax(&tcpc->dettach_temp_wake_lock);
- __pm_stay_awake(&tcpc->attach_wake_lock);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- pd_put_cc_attached_event(tcpc, tcpc->typec_attach_new);
-#endif /* CONFIG_USB_POWER_DLEIVERY */
-
- return 0;
-}
-
-static inline int tcpci_report_usb_port_detached(struct tcpc_device *tcpc)
-{
- TCPC_INFO("usb_port_detached\r\n");
-
- __pm_wakeup_event(&tcpc->dettach_temp_wake_lock,
- jiffies_to_msecs(msecs_to_jiffies(5 * 1000)));
- __pm_relax(&tcpc->attach_wake_lock);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- pd_put_cc_detached_event(tcpc);
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- return 0;
-}
-
-int tcpci_report_usb_port_changed(struct tcpc_device *tcpc)
-{
- tcpci_notify_typec_state(tcpc);
-
- if (tcpc->typec_attach_old == TYPEC_UNATTACHED)
- tcpci_report_usb_port_attached(tcpc);
- else if (tcpc->typec_attach_new == TYPEC_UNATTACHED)
- tcpci_report_usb_port_detached(tcpc);
- else
- TCPC_DBG("TCPC Attach Again\r\n");
-
- return 0;
-}
-EXPORT_SYMBOL(tcpci_report_usb_port_changed);
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Richtek TypeC Port Control Interface Core Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/version.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/gpio.h>
-#include <linux/hisi/log/hisi_log.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-#include "pd_dpm_prv.h"
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-#define TCPC_CORE_VERSION "1.1.1_G"
-
-static ssize_t tcpc_show_property(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t tcpc_store_property(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-
-#define TCPC_DEVICE_ATTR(_name, _mode) \
-{ \
- .attr = { .name = #_name, .mode = _mode }, \
- .show = tcpc_show_property, \
- .store = tcpc_store_property, \
-}
-
-static struct class *tcpc_class;
-EXPORT_SYMBOL_GPL(tcpc_class);
-
-static struct device_type tcpc_dev_type;
-
-static struct device_attribute tcpc_device_attributes[] = {
- TCPC_DEVICE_ATTR(role_def, 0444),
- TCPC_DEVICE_ATTR(rp_lvl, 0444),
- TCPC_DEVICE_ATTR(pd_test, 0664),
- TCPC_DEVICE_ATTR(info, 0444),
- TCPC_DEVICE_ATTR(timer, 0664),
- TCPC_DEVICE_ATTR(caps_info, 0444),
- TCPC_DEVICE_ATTR(cc_orient_info, 0444),
- TCPC_DEVICE_ATTR(remote_rp_lvl, 0444),
-};
-
-enum {
- TCPC_DESC_ROLE_DEF = 0,
- TCPC_DESC_RP_LEVEL,
- TCPC_DESC_PD_TEST,
- TCPC_DESC_INFO,
- TCPC_DESC_TIMER,
- TCPC_DESC_CAP_INFO,
- TCPC_DESC_CC_ORIENT_INFO,
- TCPC_DESC_REMOTE_RP_LEVEL,
-};
-
-static struct attribute *__tcpc_attrs[ARRAY_SIZE(tcpc_device_attributes) + 1];
-static struct attribute_group tcpc_attr_group = {
- .attrs = __tcpc_attrs,
-};
-
-static const struct attribute_group *tcpc_attr_groups[] = {
- &tcpc_attr_group,
- NULL,
-};
-
-static const char * const role_text[] = {
- "SNK Only",
- "SRC Only",
- "DRP",
- "Try.SRC",
- "Try.SNK",
-};
-
-static ssize_t tcpc_show_property(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct tcpc_device *tcpc = to_tcpc_device(dev);
- const ptrdiff_t offset = attr - tcpc_device_attributes;
- int i = 0;
- int vmin, vmax, ioper;
- u8 cc1, cc2;
- bool from_ic = true;
- char cc1_buf[32] = {0};
- char cc2_buf[32] = {0};
-
- switch (offset) {
- case TCPC_DESC_CC_ORIENT_INFO:
- snprintf(buf, 256, "%s\n", tcpc->typec_polarity ? "2" : "1");
- TCPC_DBG("%s typec_polarity=%s\n", __func__, buf);
- break;
- case TCPC_DESC_CAP_INFO:
- snprintf(buf + strlen(buf), 256, "%s = %d\n%s = %d\n",
- "local_selected_cap",
- tcpc->pd_port.local_selected_cap,
- "remote_selected_cap",
- tcpc->pd_port.remote_selected_cap);
-
- snprintf(buf + strlen(buf), 256, "%s\n",
- "local_src_cap(vmin, vmax, ioper)");
- for (i = 0; i < tcpc->pd_port.local_src_cap.nr; i++) {
- pd_extract_pdo_power(
- tcpc->pd_port.local_src_cap.pdos[i],
- &vmin, &vmax, &ioper);
- snprintf(buf + strlen(buf), 256, "%d %d %d\n",
- vmin, vmax, ioper);
- }
- snprintf(buf + strlen(buf), 256, "%s\n",
- "local_snk_cap(vmin, vmax, ioper)");
- for (i = 0; i < tcpc->pd_port.local_snk_cap.nr; i++) {
- pd_extract_pdo_power(
- tcpc->pd_port.local_snk_cap.pdos[i],
- &vmin, &vmax, &ioper);
- snprintf(buf + strlen(buf), 256, "%d %d %d\n",
- vmin, vmax, ioper);
- }
- snprintf(buf + strlen(buf), 256, "%s\n",
- "remote_src_cap(vmin, vmax, ioper)");
- for (i = 0; i < tcpc->pd_port.remote_src_cap.nr; i++) {
- pd_extract_pdo_power(
- tcpc->pd_port.remote_src_cap.pdos[i],
- &vmin, &vmax, &ioper);
- snprintf(buf + strlen(buf), 256, "%d %d %d\n",
- vmin, vmax, ioper);
- }
- snprintf(buf + strlen(buf), 256, "%s\n",
- "remote_snk_cap(vmin, vmax, ioper)");
- for (i = 0; i < tcpc->pd_port.remote_snk_cap.nr; i++) {
- pd_extract_pdo_power(
- tcpc->pd_port.remote_snk_cap.pdos[i],
- &vmin, &vmax, &ioper);
- snprintf(buf + strlen(buf), 256, "%d %d %d\n",
- vmin, vmax, ioper);
- }
- break;
- case TCPC_DESC_ROLE_DEF:
- snprintf(buf, 256, "%s\n", role_text[tcpc->desc.role_def]);
- break;
- case TCPC_DESC_RP_LEVEL:
- if (tcpc->typec_local_rp_level == TYPEC_CC_RP_DFT)
- snprintf(buf, 256, "%s\n", "Default");
- else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_1_5)
- snprintf(buf, 256, "%s\n", "1.5");
- else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_3_0)
- snprintf(buf, 256, "%s\n", "3.0");
- break;
- case TCPC_DESC_REMOTE_RP_LEVEL:
- tcpm_inquire_remote_cc(tcpc, &cc1, &cc2, from_ic);
-
- if (cc1 == TYPEC_CC_VOLT_OPEN)
- snprintf(cc1_buf, 256, "%s\n", "OPEN");
- else if (cc1 == TYPEC_CC_VOLT_RA)
- snprintf(cc1_buf, 256, "%s\n", "RA");
- else if (cc1 == TYPEC_CC_VOLT_RD)
- snprintf(cc1_buf, 256, "%s\n", "RD");
- else if (cc1 == TYPEC_CC_VOLT_SNK_DFT)
- snprintf(cc1_buf, 256, "%s\n", "Default");
- else if (cc1 == TYPEC_CC_VOLT_SNK_1_5)
- snprintf(cc1_buf, 256, "%s\n", "1.5");
- else if (cc1 == TYPEC_CC_VOLT_SNK_3_0)
- snprintf(cc1_buf, 256, "%s\n", "3.0");
- else if (cc1 == TYPEC_CC_DRP_TOGGLING)
- snprintf(cc1_buf, 256, "%s\n", "DRP");
- else
- snprintf(cc1_buf, 256, "%s\n", "NULL");
-
- if (cc2 == TYPEC_CC_VOLT_OPEN)
- snprintf(cc2_buf, 256, "%s\n", "OPEN");
- else if (cc2 == TYPEC_CC_VOLT_RA)
- snprintf(cc2_buf, 256, "%s\n", "RA");
- else if (cc2 == TYPEC_CC_VOLT_RD)
- snprintf(cc2_buf, 256, "%s\n", "RD");
- else if (cc2 == TYPEC_CC_VOLT_SNK_DFT)
- snprintf(cc2_buf, 256, "%s\n", "Default");
- else if (cc2 == TYPEC_CC_VOLT_SNK_1_5)
- snprintf(cc2_buf, 256, "%s\n", "1.5");
- else if (cc2 == TYPEC_CC_VOLT_SNK_3_0)
- snprintf(cc2_buf, 256, "%s\n", "3.0");
- else if (cc2 == TYPEC_CC_DRP_TOGGLING)
- snprintf(cc2_buf, 256, "%s\n", "DRP");
- else
- snprintf(cc1_buf, 256, "%s\n", "NULL");
-
- snprintf(buf, 256, " cc1 %s cc2 %s\n", cc1_buf, cc2_buf);
-
- break;
- case TCPC_DESC_PD_TEST:
- snprintf(buf,
- 256, "%s\n%s\n%s\n%s\n%s\n", "1: Power Role Swap Test",
- "2: Data Role Swap Test", "3: Vconn Swap Test",
- "4: soft reset", "5: hard reset");
- break;
- case TCPC_DESC_INFO:
- i += snprintf(buf + i,
- 256, "|^|==( %s info )==|^|\n", tcpc->desc.name);
- i += snprintf(buf + i,
- 256, "role = %s\n", role_text[tcpc->desc.role_def]);
- if (tcpc->typec_local_rp_level == TYPEC_CC_RP_DFT)
- i += snprintf(buf + i, 256, "rplvl = %s\n", "Default");
- else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_1_5)
- i += snprintf(buf + i, 256, "rplvl = %s\n", "1.5");
- else if (tcpc->typec_local_rp_level == TYPEC_CC_RP_3_0)
- i += snprintf(buf + i, 256, "rplvl = %s\n", "3.0");
- break;
- default:
- break;
- }
- return strlen(buf);
-}
-
-static int get_parameters(char *buf, long int *param1, int num_of_par)
-{
- char *token;
- int base, cnt;
-
- token = strsep(&buf, " ");
-
- for (cnt = 0; cnt < num_of_par; cnt++) {
- if (token) {
- if ((token[1] == 'x') || (token[1] == 'X'))
- base = 16;
- else
- base = 10;
-
- if (kstrtoul(token, base, ¶m1[cnt]) != 0)
- return -EINVAL;
-
- token = strsep(&buf, " ");
- } else {
- return -EINVAL;
- }
- }
- return 0;
-}
-
-static ssize_t tcpc_store_property(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct tcpc_device *tcpc = to_tcpc_device(dev);
- struct tcpm_power_cap cap;
- const ptrdiff_t offset = attr - tcpc_device_attributes;
- int ret;
- long int val;
-
- switch (offset) {
- case TCPC_DESC_ROLE_DEF:
- ret = get_parameters((char *)buf, &val, 1);
- if (ret < 0) {
- dev_err(dev, "get parameters fail\n");
- return -EINVAL;
- }
-
- tcpm_typec_change_role(tcpc, val);
- break;
- case TCPC_DESC_TIMER:
- ret = get_parameters((char *)buf, &val, 1);
- if (ret < 0) {
- dev_err(dev, "get parameters fail\n");
- return -EINVAL;
- }
- #ifdef CONFIG_USB_POWER_DELIVERY
- if (val > 0 && val <= PD_PE_TIMER_END_ID)
- pd_enable_timer(&tcpc->pd_port, val);
- else if (val > PD_PE_TIMER_END_ID && val < PD_TIMER_NR)
- tcpc_enable_timer(tcpc, val);
- #else
- if (val > 0 && val < PD_TIMER_NR)
- tcpc_enable_timer(tcpc, val);
- #endif /* CONFIG_USB_POWER_DELIVERY */
- break;
- #ifdef CONFIG_USB_POWER_DELIVERY
- case TCPC_DESC_PD_TEST:
- ret = get_parameters((char *)buf, &val, 1);
- if (ret < 0) {
- dev_err(dev, "get parameters fail\n");
- return -EINVAL;
- }
- switch (val) {
- case 1: /* Power Role Swap */
- tcpm_power_role_swap(tcpc);
- break;
- case 2: /* Data Role Swap */
- tcpm_data_role_swap(tcpc);
- break;
- case 3: /* Vconn Swap */
- tcpm_vconn_swap(tcpc);
- break;
- case 4: /* Software Reset */
- tcpm_soft_reset(tcpc);
- break;
- case 5: /* Hardware Reset */
- tcpm_hard_reset(tcpc);
- break;
- case 6:
- tcpm_get_source_cap(tcpc, &cap);
- break;
- case 7:
- tcpm_get_sink_cap(tcpc, &cap);
- break;
- default:
- break;
- }
- break;
- #endif /* CONFIG_USB_POWER_DELIVERY */
- default:
- break;
- }
- return count;
-}
-
-static int tcpc_match_device_by_name(struct device *dev, const void *data)
-{
- const char *name = data;
- struct tcpc_device *tcpc = dev_get_drvdata(dev);
-
- return strcmp(tcpc->desc.name, name) == 0;
-}
-
-struct tcpc_device *tcpc_dev_get_by_name(const char *name)
-{
- struct device *dev = class_find_device(tcpc_class,
- NULL, (const void *)name, tcpc_match_device_by_name);
- return dev ? dev_get_drvdata(dev) : NULL;
-}
-
-static void tcpc_device_release(struct device *dev)
-{
- struct tcpc_device *tcpc_dev = to_tcpc_device(dev);
- char buf[1024] = { 0 };
-
- pr_info("%s : %s device release\n", __func__, dev_name(dev));
- if (!tcpc_dev)
- snprintf(buf, sizeof(buf), "the tcpc device is NULL\n");
- /* Un-init pe thread */
-#ifdef CONFIG_USB_POWER_DELIVERY
- tcpci_event_deinit(tcpc_dev);
-#endif /* CONFIG_USB_POWER_DELIVERY */
- /* Un-init timer thread */
- tcpci_timer_deinit(tcpc_dev);
- /* Un-init Mutex */
- /* Do initialization */
- devm_kfree(dev, tcpc_dev);
-}
-
-static int pd_dpm_wake_lock_call(struct notifier_block *dpm_nb,
- unsigned long event, void *data)
-{
- struct tcpc_device *tcpc = container_of(dpm_nb,
- struct tcpc_device, dpm_nb);
-
- switch (event) {
- case PD_WAKE_LOCK:
- __pm_stay_awake(&tcpc->attach_wake_lock);
- break;
- case PD_WAKE_UNLOCK:
- __pm_relax(&tcpc->attach_wake_lock);
- break;
- default:
- pr_info("%s unknown event (%lu)\n", __func__, event);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static void tcpc_init_work(struct work_struct *work);
-
-struct tcpc_device *tcpc_device_register(struct device *parent,
- struct tcpc_desc *tcpc_desc,
- struct tcpc_ops *ops, void *drv_data)
-{
- struct tcpc_device *tcpc;
- int ret = 0;
-
- pr_info("%s register tcpc device (%s)\n", __func__, tcpc_desc->name);
- tcpc = devm_kzalloc(parent, sizeof(*tcpc), GFP_KERNEL);
- if (!tcpc) {
- pr_err("%s : allocate tcpc memeory failed\n", __func__);
- return NULL;
- }
-
- tcpc->dev.class = tcpc_class;
- tcpc->dev.type = &tcpc_dev_type;
- tcpc->dev.parent = parent;
- tcpc->dev.release = tcpc_device_release;
- dev_set_drvdata(&tcpc->dev, tcpc);
- tcpc->drv_data = drv_data;
- dev_set_name(&tcpc->dev, tcpc_desc->name);
- tcpc->desc = *tcpc_desc;
- tcpc->ops = ops;
- tcpc->typec_local_rp_level = tcpc_desc->rp_lvl;
-
- ret = device_register(&tcpc->dev);
- if (ret) {
- kfree(tcpc);
- return ERR_PTR(ret);
- }
-
- srcu_init_notifier_head(&tcpc->evt_nh);
- INIT_DELAYED_WORK(&tcpc->init_work, tcpc_init_work);
-
- mutex_init(&tcpc->access_lock);
- mutex_init(&tcpc->typec_lock);
- mutex_init(&tcpc->timer_lock);
- sema_init(&tcpc->timer_enable_mask_lock, 1);
- sema_init(&tcpc->timer_tick_lock, 1);
-
- /* If system support "WAKE_LOCK_IDLE", */
- /* please use it instead of "WAKE_LOCK_SUSPEND" */
- wakeup_source_init(&tcpc->attach_wake_lock,
- "tcpc_attach_wakelock");
- wakeup_source_init(&tcpc->dettach_temp_wake_lock,
- "tcpc_detach_wakelock");
-
- tcpc->dpm_nb.notifier_call = pd_dpm_wake_lock_call;
- ret = register_pd_wake_unlock_notifier(&tcpc->dpm_nb);
- if (ret < 0) {
- hisilog_err("%s register_pd_wake_unlock_notifier failed\n",
- __func__);
- } else {
- hisilog_info("%s register_pd_wake_unlock_notifier OK\n",
- __func__);
- }
-
- tcpci_timer_init(tcpc);
-#ifdef CONFIG_USB_POWER_DELIVERY
- tcpci_event_init(tcpc);
- pd_core_init(tcpc);
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- return tcpc;
-}
-EXPORT_SYMBOL(tcpc_device_register);
-
-static int tcpc_device_irq_enable(struct tcpc_device *tcpc)
-{
- int ret;
-
- TCPC_DBG("%s\n", __func__);
-
- if (!tcpc->ops->init) {
- pr_err("%s Please implment tcpc ops init function\n",
- __func__);
- return -EINVAL;
- }
-
- ret = tcpci_init(tcpc, false);
- if (ret < 0) {
- pr_err("%s tcpc init fail\n", __func__);
- return ret;
- }
-
- tcpci_lock_typec(tcpc);
- ret = tcpc_typec_init(tcpc, tcpc->desc.role_def + 1);
- tcpci_unlock_typec(tcpc);
-
- if (ret < 0) {
- pr_err("%s : tcpc typec init fail\n", __func__);
- return ret;
- }
-
- pr_info("%s : tcpc irq enable OK!\n", __func__);
- return 0;
-}
-
-static int tcpc_dec_notifier_supply_num(struct tcpc_device *tcp_dev)
-{
- if (tcp_dev->desc.notifier_supply_num == 0) {
- pr_info("%s already started\n", __func__);
- return 0;
- }
-
- tcp_dev->desc.notifier_supply_num--;
- pr_info("%s supply_num = %d\n", __func__,
- tcp_dev->desc.notifier_supply_num);
-
- if (tcp_dev->desc.notifier_supply_num == 0) {
- cancel_delayed_work(&tcp_dev->init_work);
- tcpc_device_irq_enable(tcp_dev);
- }
-
- return 0;
-}
-
-struct tcpc_device *notify_tcp_dev_ready(const char *name)
-{
- struct tcpc_device *tcpc = tcpc_dev_get_by_name(name);
-
- if (!tcpc)
- return NULL;
-
- tcpc_dec_notifier_supply_num(tcpc);
- return tcpc;
-}
-
-static void tcpc_init_work(struct work_struct *work)
-{
- struct tcpc_device *tcpc = container_of(
- work, struct tcpc_device, init_work.work);
-
- if (tcpc->desc.notifier_supply_num == 0)
- return;
-
- pr_info("%s force start\n", __func__);
-
- tcpc->desc.notifier_supply_num = 0;
- tcpc_device_irq_enable(tcpc);
-}
-
-int tcpc_schedule_init_work(struct tcpc_device *tcpc)
-{
- if (tcpc->desc.notifier_supply_num == 0)
- return tcpc_device_irq_enable(tcpc);
-
- pr_info("%s wait %d num\n", __func__, tcpc->desc.notifier_supply_num);
-
- schedule_delayed_work(
- &tcpc->init_work, msecs_to_jiffies(30 * 1000));
- return 0;
-}
-EXPORT_SYMBOL(tcpc_schedule_init_work);
-
-int register_tcp_dev_notifier(struct tcpc_device *tcp_dev,
- struct notifier_block *nb)
-{
- int ret;
-
- ret = srcu_notifier_chain_register(&tcp_dev->evt_nh, nb);
- if (ret != 0)
- return ret;
-
- tcpc_dec_notifier_supply_num(tcp_dev);
- return ret;
-}
-EXPORT_SYMBOL(register_tcp_dev_notifier);
-
-int unregister_tcp_dev_notifier(struct tcpc_device *tcp_dev,
- struct notifier_block *nb)
-{
- return srcu_notifier_chain_unregister(&tcp_dev->evt_nh, nb);
-}
-EXPORT_SYMBOL(unregister_tcp_dev_notifier);
-
-void tcpc_device_unregister(struct device *dev, struct tcpc_device *tcpc)
-{
- if (!tcpc)
- return;
-
- tcpc_typec_deinit(tcpc);
-
- wakeup_source_trash(&tcpc->dettach_temp_wake_lock);
- wakeup_source_trash(&tcpc->attach_wake_lock);
-
- device_unregister(&tcpc->dev);
-}
-EXPORT_SYMBOL(tcpc_device_unregister);
-
-void *tcpc_get_dev_data(struct tcpc_device *tcpc)
-{
- return tcpc->drv_data;
-}
-EXPORT_SYMBOL(tcpc_get_dev_data);
-
-void tcpci_lock_typec(struct tcpc_device *tcpc)
-{
- mutex_lock(&tcpc->typec_lock);
-}
-EXPORT_SYMBOL(tcpci_lock_typec);
-
-void tcpci_unlock_typec(struct tcpc_device *tcpc)
-{
- mutex_unlock(&tcpc->typec_lock);
-}
-EXPORT_SYMBOL(tcpci_unlock_typec);
-
-static void tcpc_init_attrs(struct device_type *dev_type)
-{
- int i;
-
- dev_type->groups = tcpc_attr_groups;
- for (i = 0; i < ARRAY_SIZE(tcpc_device_attributes); i++)
- __tcpc_attrs[i] = &tcpc_device_attributes[i].attr;
-}
-
-static int __init tcpc_class_init(void)
-{
- pr_info("%s_%s\n", __func__, TCPC_CORE_VERSION);
-
- tcpc_class = class_create(THIS_MODULE, "hisi_pd");
- if (IS_ERR(tcpc_class)) {
- pr_info("Unable to create tcpc class; errno = %ld\n",
- PTR_ERR(tcpc_class));
- return PTR_ERR(tcpc_class);
- }
- tcpc_init_attrs(&tcpc_dev_type);
- //tcpc_class->suspend = NULL;
- //tcpc_class->resume = NULL;
-
- pr_info("TCPC class init OK\n");
- return 0;
-}
-
-static void __exit tcpc_class_exit(void)
-{
- class_destroy(tcpc_class);
- pr_info("TCPC class un-init OK\n");
-}
-
-subsys_initcall(tcpc_class_init);
-module_exit(tcpc_class_exit);
-
-MODULE_DESCRIPTION("Richtek TypeC Port Control Core");
-MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>");
-MODULE_VERSION(TCPC_CORE_VERSION);
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * TCPC Interface for event handler
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kthread.h>
-#include <linux/atomic.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/jiffies.h>
-#include <linux/version.h>
-#include <linux/sched/rt.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci_event.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-#ifdef CONFIG_USB_PD_POSTPONE_VDM
-static void postpone_vdm_event(struct tcpc_device *tcpc_dev)
-{
- /*
- * Postpone VDM retry event due to the retry reason
- * maybe interrupt by some PD event ....
- */
-
- pd_event_t *vdm_event = &tcpc_dev->pd_vdm_event;
-
- if (tcpc_dev->pd_pending_vdm_event && vdm_event->pd_msg) {
- tcpc_dev->pd_postpone_vdm_timeout = false;
- tcpc_restart_timer(tcpc_dev, PD_PE_VDM_POSTPONE);
- }
-}
-#endif /* CONFIG_USB_PD_POSTPONE_VDM */
-
-pd_msg_t *__pd_alloc_msg(struct tcpc_device *tcpc_dev)
-{
- int i;
- u8 mask;
- char buf[1024] = { 0 };
-
- for (i = 0, mask = 1; i < PD_MSG_BUF_SIZE; i++, mask <<= 1) {
- if ((mask & tcpc_dev->pd_msg_buffer_allocated) == 0) {
- tcpc_dev->pd_msg_buffer_allocated |= mask;
- return tcpc_dev->pd_msg_buffer + i;
- }
- }
-
- PD_ERR("pd_alloc_msg failed\r\n");
- if (true)
- snprintf(buf, sizeof(buf), "pd alloc msg failed\n");
- return (pd_msg_t *)NULL;
-}
-
-pd_msg_t *pd_alloc_msg(struct tcpc_device *tcpc_dev)
-{
- pd_msg_t *pd_msg = NULL;
-
- mutex_lock(&tcpc_dev->access_lock);
- pd_msg = __pd_alloc_msg(tcpc_dev);
- mutex_unlock(&tcpc_dev->access_lock);
-
- return pd_msg;
-}
-
-static void __pd_free_msg(struct tcpc_device *tcpc_dev, pd_msg_t *pd_msg)
-{
- int index = pd_msg - tcpc_dev->pd_msg_buffer;
- u8 mask = 1 << index;
- char buf[1024] = { 0 };
-
- if ((mask & tcpc_dev->pd_msg_buffer_allocated) == 0)
- snprintf(buf, sizeof(buf), "pd free msg failed\n");
- tcpc_dev->pd_msg_buffer_allocated &= (~mask);
-}
-
-static void __pd_free_event(struct tcpc_device *tcpc_dev, pd_event_t *pd_event)
-{
- if (pd_event->pd_msg) {
- __pd_free_msg(tcpc_dev, pd_event->pd_msg);
- pd_event->pd_msg = NULL;
- }
-}
-
-void pd_free_msg(struct tcpc_device *tcpc_dev, pd_msg_t *pd_msg)
-{
- mutex_lock(&tcpc_dev->access_lock);
- __pd_free_msg(tcpc_dev, pd_msg);
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_free_event(struct tcpc_device *tcpc_dev, pd_event_t *pd_event)
-{
- mutex_lock(&tcpc_dev->access_lock);
- __pd_free_event(tcpc_dev, pd_event);
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static bool __pd_get_event(struct tcpc_device *tcpc_dev, pd_event_t *pd_event)
-{
- int index = 0;
-
- if (tcpc_dev->pd_event_count <= 0)
- return false;
-
- tcpc_dev->pd_event_count--;
-
- *pd_event = tcpc_dev->pd_event_ring_buffer[
- tcpc_dev->pd_event_head_index];
-
- if (tcpc_dev->pd_event_count) {
- index = tcpc_dev->pd_event_head_index + 1;
- index %= PD_EVENT_BUF_SIZE;
- }
- tcpc_dev->pd_event_head_index = index;
- return true;
-}
-
-bool pd_get_event(struct tcpc_device *tcpc_dev, pd_event_t *pd_event)
-{
- bool ret;
-
- mutex_lock(&tcpc_dev->access_lock);
- ret = __pd_get_event(tcpc_dev, pd_event);
- mutex_unlock(&tcpc_dev->access_lock);
- return ret;
-}
-
-static bool __pd_put_event(struct tcpc_device *tcpc_dev,
- const pd_event_t *pd_event, bool from_port_partner)
-{
- int index;
-
-#ifdef CONFIG_USB_PD_POSTPONE_OTHER_VDM
- if (from_port_partner)
- postpone_vdm_event(tcpc_dev);
-#endif
-
- if (tcpc_dev->pd_event_count >= PD_EVENT_BUF_SIZE) {
- PD_ERR("pd_put_event failed\r\n");
- return false;
- }
-
- index = (tcpc_dev->pd_event_head_index + tcpc_dev->pd_event_count);
- index %= PD_EVENT_BUF_SIZE;
-
- tcpc_dev->pd_event_count++;
- tcpc_dev->pd_event_ring_buffer[index] = *pd_event;
-
- atomic_inc(&tcpc_dev->pending_event);
- wake_up_interruptible(&tcpc_dev->event_loop_wait_que);
- return true;
-}
-
-bool pd_put_event(struct tcpc_device *tcpc_dev, const pd_event_t *pd_event,
- bool from_port_partner)
-{
- bool ret;
-
- mutex_lock(&tcpc_dev->access_lock);
- ret = __pd_put_event(tcpc_dev, pd_event, from_port_partner);
- mutex_unlock(&tcpc_dev->access_lock);
-
- return ret;
-}
-
-/*----------------------------------------------------------------------------*/
-
-bool pd_get_vdm_event(struct tcpc_device *tcpc_dev, pd_event_t *pd_event)
-{
- pd_event_t delay_evt = {
- .event_type = PD_EVT_CTRL_MSG,
- .msg = PD_CTRL_GOOD_CRC,
- .pd_msg = NULL,
- };
-
- pd_event_t *vdm_event = &tcpc_dev->pd_vdm_event;
-
- if (tcpc_dev->pd_pending_vdm_event) {
- if (vdm_event->pd_msg && !tcpc_dev->pd_postpone_vdm_timeout)
- return false;
-
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_pending_vdm_good_crc) {
- *pd_event = delay_evt;
- tcpc_dev->pd_pending_vdm_good_crc = false;
- } else {
- *pd_event = *vdm_event;
- tcpc_dev->pd_pending_vdm_event = false;
- }
- mutex_unlock(&tcpc_dev->access_lock);
- return true;
- }
-
- return false;
-}
-
-static inline void reset_pe_vdm_state(pd_port_t *pd_port, u32 vdm_hdr)
-{
- if (PD_VDO_SVDM(vdm_hdr) && PD_VDO_CMDT(vdm_hdr) == CMDT_INIT) {
- pd_port->reset_vdm_state = true;
- pd_port->pe_vdm_state = pd_port->pe_pd_state;
- }
-}
-
-bool pd_put_vdm_event(struct tcpc_device *tcpc_dev,
- pd_event_t *pd_event, bool from_port_partner)
-{
- char buf[1024] = { 0 };
- pd_msg_t *pd_msg = pd_event->pd_msg;
-
- mutex_lock(&tcpc_dev->access_lock);
-
- if (tcpc_dev->pd_pending_vdm_event) {
- /* If message from port partner, we have to overwrite it */
-
- if (from_port_partner) {
- if (pd_event_msg_match(&tcpc_dev->pd_vdm_event,
- PD_EVT_CTRL_MSG,
- PD_CTRL_GOOD_CRC)) {
- TCPC_DBG("PostponeVDM GoodCRC\r\n");
- tcpc_dev->pd_pending_vdm_good_crc = true;
- }
-
- __pd_free_event(tcpc_dev, &tcpc_dev->pd_vdm_event);
- } else {
- __pd_free_event(tcpc_dev, pd_event);
- mutex_unlock(&tcpc_dev->access_lock);
- return false;
- }
- }
-
- tcpc_dev->pd_vdm_event = *pd_event;
- tcpc_dev->pd_pending_vdm_event = true;
- tcpc_dev->pd_postpone_vdm_timeout = true;
-
- if (from_port_partner) {
- if (!pd_msg)
- snprintf(buf, sizeof(buf), "the pd_msg is NULL\n");
- /* pd_msg->time_stamp = 0; */
- tcpc_dev->pd_last_vdm_msg = *pd_msg;
- reset_pe_vdm_state(&tcpc_dev->pd_port, pd_msg->payload[0]);
-#ifdef CONFIG_USB_PD_POSTPONE_FIRST_VDM
- postpone_vdm_event(tcpc_dev);
- mutex_unlock(&tcpc_dev->access_lock);
- return true;
-#endif /* CONFIG_USB_PD_POSTPONE_FIRST_VDM */
- }
-
- atomic_inc(&tcpc_dev->pending_event); /* do not really wake up process*/
- wake_up_interruptible(&tcpc_dev->event_loop_wait_que);
- mutex_unlock(&tcpc_dev->access_lock);
-
- return true;
-}
-
-bool pd_put_last_vdm_event(struct tcpc_device *tcpc_dev)
-{
- pd_msg_t *pd_msg = &tcpc_dev->pd_last_vdm_msg;
- pd_event_t *vdm_event = &tcpc_dev->pd_vdm_event;
-
- mutex_lock(&tcpc_dev->access_lock);
-
- vdm_event->event_type = PD_EVT_HW_MSG;
- vdm_event->msg = PD_HW_RETRY_VDM;
-
- if (tcpc_dev->pd_pending_vdm_event)
- __pd_free_event(tcpc_dev, &tcpc_dev->pd_vdm_event);
-
- vdm_event->pd_msg = __pd_alloc_msg(tcpc_dev);
-
- if (!vdm_event->pd_msg) {
- mutex_unlock(&tcpc_dev->access_lock);
- return false;
- }
-
- *vdm_event->pd_msg = *pd_msg;
- tcpc_dev->pd_pending_vdm_event = true;
- tcpc_dev->pd_postpone_vdm_timeout = true;
-
-#ifdef CONFIG_USB_PD_POSTPONE_RETRY_VDM
- reset_pe_vdm_state(&tcpc_dev->pd_port, pd_msg->payload[0]);
- postpone_vdm_event(tcpc_dev);
-#else
- atomic_inc(&tcpc_dev->pending_event); /* do not really wake up process*/
- wake_up_interruptible(&tcpc_dev->event_loop_wait_que);
-#endif /* CONFIG_USB_PD_POSTPONE_RETRY_VDM */
-
- mutex_unlock(&tcpc_dev->access_lock);
- return true;
-}
-
-/*----------------------------------------------------------------------------*/
-
-static void __pd_event_buf_reset(struct tcpc_device *tcpc_dev)
-{
- pd_event_t pd_event;
-
- tcpc_dev->pd_hard_reset_event_pending = false;
- while (__pd_get_event(tcpc_dev, &pd_event))
- __pd_free_event(tcpc_dev, &pd_event);
-
- if (tcpc_dev->pd_pending_vdm_event) {
- __pd_free_event(tcpc_dev, &tcpc_dev->pd_vdm_event);
- tcpc_dev->pd_pending_vdm_event = false;
- }
-
- tcpc_dev->pd_pending_vdm_good_crc = false;
-}
-
-void pd_event_buf_reset(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
- __pd_event_buf_reset(tcpc_dev);
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static inline bool __pd_put_hw_event(
- struct tcpc_device *tcpc_dev, u8 hw_event)
-{
- pd_event_t evt = {
- .event_type = PD_EVT_HW_MSG,
- .msg = hw_event,
- .pd_msg = NULL,
- };
-
- return __pd_put_event(tcpc_dev, &evt, false);
-}
-
-static inline bool __pd_put_pe_event(
- struct tcpc_device *tcpc_dev, u8 pe_event)
-{
- pd_event_t evt = {
- .event_type = PD_EVT_PE_MSG,
- .msg = pe_event,
- .pd_msg = NULL,
- };
-
- return __pd_put_event(tcpc_dev, &evt, false);
-}
-
-void pd_put_cc_detached_event(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
-
- __pd_event_buf_reset(tcpc_dev);
- __pd_put_hw_event(tcpc_dev, PD_HW_CC_DETACHED);
-
- tcpc_dev->pd_wait_pe_idle = true;
- tcpc_dev->pd_wait_pr_swap_complete = false;
- tcpc_dev->pd_wait_hard_reset_complete = false;
- tcpc_dev->pd_hard_reset_event_pending = false;
- tcpc_dev->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
- tcpc_dev->pd_bist_mode = PD_BIST_MODE_DISABLE;
- tcpc_dev->pd_ping_event_pending = false;
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- tcpc_dev->pd_discard_pending = false;
-#endif
-
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_put_recv_hard_reset_event(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
-
- tcpc_dev->pd_transmit_state = PD_TX_STATE_HARD_RESET;
-
- if ((!tcpc_dev->pd_hard_reset_event_pending) &&
- (!tcpc_dev->pd_wait_pe_idle)) {
- __pd_event_buf_reset(tcpc_dev);
- __pd_put_hw_event(tcpc_dev, PD_HW_RECV_HARD_RESET);
- tcpc_dev->pd_bist_mode = PD_BIST_MODE_DISABLE;
- tcpc_dev->pd_hard_reset_event_pending = true;
- tcpc_dev->pd_ping_event_pending = false;
- }
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- tcpc_dev->pd_discard_pending = false;
-#endif
-
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_put_sent_hard_reset_event(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_wait_hard_reset_complete) {
- tcpc_dev->pd_transmit_state = PD_TX_STATE_GOOD_CRC;
- __pd_event_buf_reset(tcpc_dev);
- __pd_put_pe_event(tcpc_dev, PD_PE_HARD_RESET_COMPLETED);
- } else {
- TCPC_DBG("[HReset] Unattached\r\n");
- }
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-bool pd_put_pd_msg_event(struct tcpc_device *tcpc_dev, pd_msg_t *pd_msg)
-{
- u32 cnt, cmd;
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- bool discard_pending = false;
-#endif
-
- pd_event_t evt = {
- .event_type = PD_EVT_PD_MSG,
- .pd_msg = pd_msg,
- };
-
- cnt = PD_HEADER_CNT(pd_msg->msg_hdr);
- cmd = PD_HEADER_TYPE(pd_msg->msg_hdr);
-
- /* bist mode */
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_bist_mode != PD_BIST_MODE_DISABLE) {
- TCPC_DBG("BIST_MODE_RX\r\n");
- __pd_free_event(tcpc_dev, &evt);
- mutex_unlock(&tcpc_dev->access_lock);
- return 0;
- }
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- if (tcpc_dev->pd_discard_pending &&
- (pd_msg->frame_type == TCPC_TX_SOP) &&
- (tcpc_dev->tcpc_flags & TCPC_FLAGS_RETRY_CRC_DISCARD)) {
- discard_pending = true;
- tcpc_dev->pd_discard_pending = false;
-
- if ((cmd == PD_CTRL_GOOD_CRC) && (cnt == 0)) {
- TCPC_DBG("RETRANSMIT\r\n");
- __pd_free_event(tcpc_dev, &evt);
- mutex_unlock(&tcpc_dev->access_lock);
-
- /* TODO: check it later */
- tcpc_disable_timer(tcpc_dev, PD_TIMER_DISCARD);
- tcpci_retransmit(tcpc_dev);
- return 0;
- }
- }
-#endif
-
-#ifdef CONFIG_USB_PD_DROP_REPEAT_PING
- if (cnt == 0 && cmd == PD_CTRL_PING) {
- if (tcpc_dev->pd_ping_event_pending) {
- TCPC_DBG("PING\r\n");
- __pd_free_event(tcpc_dev, &evt);
- mutex_unlock(&tcpc_dev->access_lock);
- return 0;
- }
-
- tcpc_dev->pd_ping_event_pending = true;
- }
-#endif
-
- if (cnt != 0 && cmd == PD_DATA_BIST)
- tcpc_dev->pd_bist_mode = PD_BIST_MODE_EVENT_PENDING;
-
- mutex_unlock(&tcpc_dev->access_lock);
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- if (discard_pending) {
- tcpc_disable_timer(tcpc_dev, PD_TIMER_DISCARD);
- pd_put_hw_event(tcpc_dev, PD_HW_TX_FAILED);
- }
-#endif
-
- if (cnt != 0 && cmd == PD_DATA_VENDOR_DEF)
- return pd_put_vdm_event(tcpc_dev, &evt, true);
- return pd_put_event(tcpc_dev, &evt, true);
-}
-
-static void pd_report_vbus_present(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
- __pd_put_hw_event(tcpc_dev, PD_HW_VBUS_PRESENT);
-}
-
-void pd_put_vbus_changed_event(struct tcpc_device *tcpc_dev, bool from_ic)
-{
- int vbus_valid;
- bool postpone_vbus_present = false;
-
- mutex_lock(&tcpc_dev->access_lock);
- vbus_valid = tcpci_check_vbus_valid(tcpc_dev);
-
- switch (tcpc_dev->pd_wait_vbus_once) {
- case PD_WAIT_VBUS_VALID_ONCE:
- if (vbus_valid) {
-#if CONFIG_USB_PD_VBUS_PRESENT_TOUT
- postpone_vbus_present = from_ic;
-#endif /* CONFIG_USB_PD_VBUS_PRESENT_TOUT */
- if (!postpone_vbus_present)
- pd_report_vbus_present(tcpc_dev);
- }
- break;
-
- case PD_WAIT_VBUS_INVALID_ONCE:
- if (!vbus_valid) {
- tcpc_dev->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
- __pd_put_hw_event(tcpc_dev, PD_HW_VBUS_ABSENT);
- }
- break;
- }
- mutex_unlock(&tcpc_dev->access_lock);
-
-#if CONFIG_USB_PD_VBUS_PRESENT_TOUT
- if (postpone_vbus_present)
- tcpc_enable_timer(tcpc_dev, PD_TIMER_VBUS_PRESENT);
-#endif /* CONFIG_USB_PD_VBUS_PRESENT_TOUT */
-}
-
-void pd_put_vbus_safe0v_event(struct tcpc_device *tcpc_dev)
-{
-#ifdef CONFIG_USB_PD_SAFE0V_TIMEOUT
- tcpc_disable_timer(tcpc_dev, PD_TIMER_VSAFE0V_TOUT);
-#endif /* CONFIG_USB_PD_SAFE0V_TIMEOUT */
-
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_wait_vbus_once == PD_WAIT_VBUS_SAFE0V_ONCE) {
- tcpc_dev->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
- __pd_put_hw_event(tcpc_dev, PD_HW_VBUS_SAFE0V);
- }
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_put_vbus_stable_event(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_wait_vbus_once == PD_WAIT_VBUS_STABLE_ONCE) {
- tcpc_dev->pd_wait_vbus_once = PD_WAIT_VBUS_DISABLE;
- __pd_put_hw_event(tcpc_dev, PD_HW_VBUS_STABLE);
- }
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_put_vbus_present_event(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->access_lock);
- pd_report_vbus_present(tcpc_dev);
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-/* ---- PD Notify TCPC ---- */
-
-void pd_try_put_pe_idle_event(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_transmit_state <= PD_TX_STATE_WAIT)
- __pd_put_pe_event(tcpc_dev, PD_PE_IDLE);
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_idle(pd_port_t *pd_port)
-{
- bool notify_pe_idle = false;
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- if (tcpc_dev->pd_wait_pe_idle) {
- notify_pe_idle = true;
- tcpc_dev->pd_wait_pe_idle = false;
- }
-
- tcpc_dev->pd_wait_error_recovery = false;
- mutex_unlock(&tcpc_dev->access_lock);
-
- pd_update_connect_state(pd_port, PD_CONNECT_NONE);
-
- if (notify_pe_idle)
- tcpc_enable_timer(tcpc_dev, TYPEC_RT_TIMER_PE_IDLE);
-}
-
-void pd_notify_pe_wait_vbus_once(pd_port_t *pd_port, int wait_evt)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_vbus_once = wait_evt;
- mutex_unlock(&tcpc_dev->access_lock);
-
- switch (wait_evt) {
- case PD_WAIT_VBUS_VALID_ONCE:
- case PD_WAIT_VBUS_INVALID_ONCE:
- pd_put_vbus_changed_event(tcpc_dev, false);
- break;
- case PD_WAIT_VBUS_SAFE0V_ONCE:
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT
- if (tcpci_check_vsafe0v(tcpc_dev, true)) {
- pd_put_vbus_safe0v_event(tcpc_dev);
- break;
- }
-#else
- pd_enable_timer(pd_port, PD_TIMER_VSAFE0V_DELAY);
-#endif /* CONFIG_TCPC_VSAFE0V_DETECT */
-
-#ifdef CONFIG_USB_PD_SAFE0V_TIMEOUT
- pd_enable_timer(pd_port, PD_TIMER_VSAFE0V_TOUT);
-#endif /* CONFIG_USB_PD_SAFE0V_TIMEOUT */
- break;
- }
-}
-
-void pd_notify_pe_error_recovery(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_hard_reset_complete = false;
- tcpc_dev->pd_wait_pr_swap_complete = false;
- tcpc_dev->pd_wait_error_recovery = true;
- mutex_unlock(&tcpc_dev->access_lock);
-
- tcpci_set_cc(pd_port->tcpc_dev, TYPEC_CC_OPEN);
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_ERROR_RECOVERY);
-}
-
-void pd_notify_pe_transit_to_default(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_hard_reset_event_pending = false;
- tcpc_dev->pd_wait_hard_reset_complete = true;
- tcpc_dev->pd_wait_pr_swap_complete = false;
- tcpc_dev->pd_bist_mode = PD_BIST_MODE_DISABLE;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_hard_reset_completed(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- if (!tcpc_dev->pd_wait_hard_reset_complete)
- return;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_hard_reset_complete = false;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_send_hard_reset(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_transmit_state = PD_TX_STATE_WAIT_HARD_RESET;
- tcpc_dev->pd_wait_hard_reset_complete = true;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_execute_pr_swap(pd_port_t *pd_port, bool start_swap)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- pd_port->during_swap = start_swap;
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_pr_swap_complete = true;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_cancel_pr_swap(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- if (!tcpc_dev->pd_wait_pr_swap_complete)
- return;
-
- pd_port->during_swap = false;
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_pr_swap_complete = false;
- mutex_unlock(&tcpc_dev->access_lock);
-
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
-}
-
-void pd_notify_pe_reset_protocol(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_pr_swap_complete = false;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_noitfy_pe_bist_mode(pd_port_t *pd_port, u8 mode)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_bist_mode = mode;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_recv_ping_event(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_ping_event_pending = false;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_transmit_msg(
- pd_port_t *pd_port, u8 type)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_transmit_state = type;
- mutex_unlock(&tcpc_dev->access_lock);
-}
-
-void pd_notify_pe_pr_changed(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- /* Check mutex later, actually,
- * typec layer will igrone all cc-change during PR-SWAP
- */
-
- /* mutex_lock(&tcpc_dev->access_lock); */
- tcpc_typec_handle_pe_pr_swap(tcpc_dev);
- /* mutex_unlock(&tcpc_dev->access_lock); */
-}
-
-void pd_notify_pe_src_explicit_contract(pd_port_t *pd_port)
-{
- struct tcpc_device *tcpc_dev = pd_port->tcpc_dev;
-
- if (pd_port->explicit_contract)
- return;
-
- /*mutex_lock(&tcpc_dev->access_lock); */
- tcpc_typec_advertise_explicit_contract(tcpc_dev);
- /*mutex_unlock(&tcpc_dev->access_lock); */
-}
-
-/* ---- init ---- */
-static int tcpc_event_thread(void *param)
-{
- struct tcpc_device *tcpc_dev = param;
- struct sched_param sch_param = {.sched_priority = MAX_RT_PRIO - 2};
-
- sched_setscheduler(current, SCHED_FIFO, &sch_param);
-
- while (true) {
- wait_event_interruptible(
- tcpc_dev->event_loop_wait_que,
- atomic_read(&tcpc_dev->pending_event) |
- tcpc_dev->event_loop_thead_stop);
- if (kthread_should_stop() || tcpc_dev->event_loop_thead_stop)
- break;
- do {
- atomic_dec_if_positive(&tcpc_dev->pending_event);
- } while (pd_policy_engine_run(tcpc_dev));
- }
-
- return 0;
-}
-
-int tcpci_event_init(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->event_task = kthread_create(tcpc_event_thread, tcpc_dev,
- "tcpc_event_%s.%p", dev_name(&tcpc_dev->dev), tcpc_dev);
- tcpc_dev->event_loop_thead_stop = false;
-
- init_waitqueue_head(&tcpc_dev->event_loop_wait_que);
- atomic_set(&tcpc_dev->pending_event, 0);
- wake_up_process(tcpc_dev->event_task);
-
- return 0;
-}
-
-int tcpci_event_deinit(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->event_loop_thead_stop = true;
- wake_up_interruptible(&tcpc_dev->event_loop_wait_que);
- kthread_stop(tcpc_dev->event_task);
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * TCPC Interface for timer handler
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/atomic.h>
-#include <linux/kthread.h>
-#include <linux/hrtimer.h>
-#include <linux/version.h>
-#include <linux/sched/rt.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_timer.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/rt1711h.h>
-
-#define RT_MASK64(i) (((u64)1) << i)
-
-#define TIMEOUT_VAL(val) (val * 1000)
-#define TIMEOUT_RANGE(min, max) ((min * 4000 + max * 1000) / 5)
-#define TIMEOUT_VAL_US(val) (val)
-
-/* Debug message Macro */
-#if TCPC_TIMER_DBG_EN
-#define TCPC_TIMER_DBG(tcpc, id) \
-{ \
- RT_DBG_INFO("Trigger %s\n", tcpc_timer_name[id]); \
-}
-#else
-#define TCPC_TIMER_DBG(format, args...)
-#endif /* TCPC_TIMER_DBG_EN */
-
-#if TCPC_TIMER_INFO_EN
-#define TCPC_TIMER_EN_DBG(tcpc, id) \
-{ \
- RT_DBG_INFO("Enable %s\n", tcpc_timer_name[id]); \
-}
-#else
-#define TCPC_TIMER_EN_DBG(format, args...)
-#endif /* TCPC_TIMER_INFO_EN */
-
-static inline u64 rt_get_value(u64 *p)
-{
- unsigned long flags;
- u64 data;
-
- raw_local_irq_save(flags);
- data = *p;
- raw_local_irq_restore(flags);
- return data;
-}
-
-static inline void rt_set_value(u64 *p, u64 data)
-{
- unsigned long flags;
-
- raw_local_irq_save(flags);
- *p = data;
- raw_local_irq_restore(flags);
-}
-
-static inline void rt_clear_bit(int nr, u64 *addr)
-{
- u64 mask = ((u64)1) << nr;
- unsigned long flags;
-
- raw_local_irq_save(flags);
- *addr &= ~mask;
- raw_local_irq_restore(flags);
-}
-
-static inline void rt_set_bit(int nr, u64 *addr)
-{
- u64 mask = ((u64)1) << nr;
- unsigned long flags;
-
- raw_local_irq_save(flags);
- *addr |= mask;
- raw_local_irq_restore(flags);
-}
-
-const char *tcpc_timer_name[] = {
-#ifdef CONFIG_USB_POWER_DELIVERY
- "PD_TIMER_BIST_CONT_MODE",
- "PD_TIMER_DISCOVER_ID",
- "PD_TIMER_HARD_RESET_COMPLETE",
- "PD_TIMER_NO_RESPONSE",
- "PD_TIMER_PS_HARD_RESET",
- "PD_TIMER_PS_SOURCE_OFF",
- "PD_TIMER_PS_SOURCE_ON",
- "PD_TIMER_PS_TRANSITION",
- "PD_TIMER_SENDER_RESPONSE",
- "PD_TIMER_SINK_ACTIVITY",
- "PD_TIMER_SINK_REQUEST",
- "PD_TIMER_SINK_WAIT_CAP",
- "PD_TIMER_SOURCE_ACTIVITY",
- "PD_TIMER_SOURCE_CAPABILITY",
- "PD_TIMER_SOURCE_START",
- "PD_TIMER_VCONN_ON",
- "PD_TIMER_VDM_MODE_ENTRY",
- "PD_TIMER_VDM_MODE_EXIT",
- "PD_TIMER_VDM_RESPONSE",
- "PD_TIMER_SOURCE_TRANSITION",
- "PD_TIMER_SRC_RECOVER",
- "PD_TIMER_VSAFE0V_DELAY",
- "PD_TIMER_VSAFE0V_TOUT",
- "PD_TIMER_DISCARD",
- "PD_TIMER_VBUS_STABLE",
- "PD_TIMER_VBUS_PRESENT",
- "PD_PE_VDM_POSTPONE",
-
- "TYPEC_RT_TIMER_PE_IDLE",
- "TYPEC_RT_TIMER_SAFE0V_DELAY",
- "TYPEC_RT_TIMER_SAFE0V_TOUT",
-
- "TYPEC_TRY_TIMER_DRP_TRY",
- "TYPEC_TRY_TIMER_DRP_TRYWAIT",
-
- "TYPEC_TIMER_CCDEBOUNCE",
- "TYPEC_TIMER_PDDEBOUNCE",
- "TYPEC_TIMER_ERROR_RECOVERY",
- "TYPEC_TIMER_WAKEUP_TOUT",
- "TYPEC_TIMER_DRP_SRC_TOGGLE",
-#else
- "TYPEC_RT_TIMER_SAFE0V_DELAY",
- "TYPEC_RT_TIMER_SAFE0V_TOUT",
-
- "TYPEC_TRY_TIMER_DRP_TRY",
- "TYPEC_TRY_TIMER_DRP_TRYWAIT",
-
- "TYPEC_TIMER_CCDEBOUNCE",
- "TYPEC_TIMER_PDDEBOUNCE",
- "TYPEC_TIMER_WAKEUP_TOUT",
- "TYPEC_TIMER_DRP_SRC_TOGGLE",
-#endif /* CONFIG_USB_POWER_DELIVERY */
-};
-
-#define PD_TIMER_VSAFE0V_DLY_TOUT TIMEOUT_VAL(400)
-
-#ifdef CONFIG_TCPC_VSAFE0V_DETECT
-#define TYPEC_RT_TIMER_SAFE0V_DLY_TOUT TIMEOUT_VAL(35)
-#else
-#define TYPEC_RT_TIMER_SAFE0V_DLY_TOUT TIMEOUT_VAL(100)
-#endif
-
-static const u32 tcpc_timer_timeout[PD_TIMER_NR] = {
-#ifdef CONFIG_USB_POWER_DELIVERY
- TIMEOUT_RANGE(30, 60), /* PD_TIMER_BIST_CONT_MODE */
- TIMEOUT_RANGE(40, 50), /* PD_TIMER_DISCOVER_ID */
- TIMEOUT_RANGE(4, 5), /* PD_TIMER_HARD_RESET_COMPLETE (no used) */
- TIMEOUT_RANGE(4500, 5500), /* PD_TIMER_NO_RESPONSE */
- TIMEOUT_RANGE(25, 35), /* PD_TIMER_PS_HARD_RESET */
- TIMEOUT_RANGE(750, 920), /* PD_TIMER_PS_SOURCE_OFF */
- TIMEOUT_RANGE(390, 480), /* PD_TIMER_PS_SOURCE_ON, */
- TIMEOUT_RANGE(450, 550), /* PD_TIMER_PS_TRANSITION */
- TIMEOUT_RANGE(24, 30), /* PD_TIMER_SENDER_RESPONSE */
- TIMEOUT_RANGE(120, 150), /* PD_TIMER_SINK_ACTIVITY (no used) */
- TIMEOUT_RANGE(100, 100), /* PD_TIMER_SINK_REQUEST */
- TIMEOUT_RANGE(310, 620), /* PD_TIMER_SINK_WAIT_CAP */
- TIMEOUT_RANGE(40, 50), /* PD_TIMER_SOURCE_ACTIVITY (no used) */
- TIMEOUT_RANGE(100, 200), /* PD_TIMER_SOURCE_CAPABILITY */
- TIMEOUT_VAL(20), /* PD_TIMER_SOURCE_START */
- TIMEOUT_VAL(100), /* PD_TIMER_VCONN_ON */
- TIMEOUT_RANGE(40, 50), /* PD_TIMER_VDM_MODE_ENTRY */
- TIMEOUT_RANGE(40, 50), /* PD_TIMER_VDM_MODE_EXIT */
- TIMEOUT_RANGE(24, 30), /* PD_TIMER_VDM_RESPONSE */
- TIMEOUT_RANGE(25, 35), /* PD_TIMER_SOURCE_TRANSITION */
- TIMEOUT_RANGE(660, 1000), /* PD_TIMER_SRC_RECOVER */
-
- /* PD_TIMER (out of spec) */
- PD_TIMER_VSAFE0V_DLY_TOUT, /* PD_TIMER_VSAFE0V_DELAY */
- TIMEOUT_VAL(650), /* PD_TIMER_VSAFE0V_TOUT */
- TIMEOUT_VAL(3), /* PD_TIMER_DISCARD */
- /* PD_TIMER_VBUS_STABLE */
- TIMEOUT_VAL(CONFIG_USB_PD_VBUS_STABLE_TOUT),
- /* PD_TIMER_VBUS_PRESENT */
- TIMEOUT_VAL(CONFIG_USB_PD_VBUS_PRESENT_TOUT),
- TIMEOUT_VAL_US(3500), /* PD_PE_VDM_POSTPONE */
-
- /* TYPEC-RT-TIMER */
- TIMEOUT_VAL(1), /* TYPEC_RT_TIMER_PE_IDLE */
- TYPEC_RT_TIMER_SAFE0V_DLY_TOUT, /* TYPEC_RT_TIMER_SAFE0V_DELAY */
- TIMEOUT_VAL(650), /* TYPEC_RT_TIMER_SAFE0V_TOUT */
-
- /* TYPEC-TRY-TIMER */
- TIMEOUT_RANGE(75, 150), /* TYPEC_TRY_TIMER_DRP_TRY */
- TIMEOUT_RANGE(400, 800), /* TYPEC_TRY_TIMER_DRP_TRYWAIT */
-
- /* TYPEC-DEBOUNCE-TIMER */
- TIMEOUT_RANGE(100, 200), /* TYPEC_TIMER_CCDEBOUNCE */
- TIMEOUT_RANGE(10, 10), /* TYPEC_TIMER_PDDEBOUNCE */
- TIMEOUT_RANGE(25, 25), /* TYPEC_TIMER_ERROR_RECOVERY */
- /* TYPEC_TIMER_WAKEUP_TOUT (out of spec) */
- TIMEOUT_VAL(300 * 1000),
- TIMEOUT_VAL(60), /* TYPEC_TIMER_DRP_SRC_TOGGLE */
-#else
- /* TYPEC-RT-TIMER */
- TYPEC_RT_TIMER_SAFE0V_DLY_TOUT, /* TYPEC_RT_TIMER_SAFE0V_DELAY */
- TIMEOUT_VAL(650), /* TYPEC_RT_TIMER_SAFE0V_TOUT */
-
- /* TYPEC-TRY-TIMER */
- TIMEOUT_RANGE(75, 150), /* TYPEC_TRY_TIMER_DRP_TRY */
- TIMEOUT_RANGE(400, 800), /* TYPEC_TRY_TIMER_DRP_TRYWAIT */
-
- TIMEOUT_RANGE(100, 200), /* TYPEC_TIMER_CCDEBOUNCE */
- TIMEOUT_RANGE(10, 10), /* TYPEC_TIMER_PDDEBOUNCE */
- TYPEC_TIMER_SAFE0V_TOUT, /* TYPEC_TIMER_SAFE0V (out of spec) */
- /* TYPEC_TIMER_WAKEUP_TOUT (out of spec) */
- TIMEOUT_VAL(300 * 1000),
- TIMEOUT_VAL(60), /* TYPEC_TIMER_DRP_SRC_TOGGLE */
-#endif /* CONFIG_USB_POWER_DELIVERY */
-};
-
-typedef enum hrtimer_restart (*tcpc_hrtimer_call)(struct hrtimer *timer);
-
-static inline void on_pe_timer_timeout(
- struct tcpc_device *tcpc_dev, u32 timer_id)
-{
-#ifdef CONFIG_USB_POWER_DELIVERY
- pd_event_t pd_event;
-
- pd_event.event_type = PD_EVT_TIMER_MSG;
- pd_event.msg = timer_id;
- pd_event.pd_msg = NULL;
-
- switch (timer_id) {
- case PD_TIMER_VDM_MODE_ENTRY:
- case PD_TIMER_VDM_MODE_EXIT:
- case PD_TIMER_VDM_RESPONSE:
- pd_put_vdm_event(tcpc_dev, &pd_event, false);
- break;
-
- case PD_TIMER_VSAFE0V_DELAY:
- pd_put_vbus_safe0v_event(tcpc_dev);
- break;
-
-#ifdef CONFIG_USB_PD_SAFE0V_TIMEOUT
- case PD_TIMER_VSAFE0V_TOUT:
- {
- u16 power_status = 0;
- int vbus_level = tcpc_dev->vbus_level;
-
- tcpci_get_power_status(tcpc_dev, &power_status);
- tcpci_vbus_level_init(tcpc_dev, power_status);
-
- TCPC_INFO("VSafe0V TOUT: %d - %d\r\n",
- tcpc_dev->vbus_level, vbus_level);
- }
- pd_put_vbus_safe0v_event(tcpc_dev);
- break;
-#endif /* CONFIG_USB_PD_SAFE0V_TIMEOUT */
-
-#ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD
- case PD_TIMER_DISCARD:
- tcpc_dev->pd_discard_pending = false;
- pd_put_hw_event(tcpc_dev, PD_HW_TX_FAILED);
- break;
-#endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */
-
-#if CONFIG_USB_PD_VBUS_STABLE_TOUT
- case PD_TIMER_VBUS_STABLE:
- pd_put_vbus_stable_event(tcpc_dev);
- break;
-#endif /* CONFIG_USB_PD_VBUS_STABLE_TOUT */
-
-#if CONFIG_USB_PD_VBUS_PRESENT_TOUT
- case PD_TIMER_VBUS_PRESENT:
- pd_put_vbus_present_event(tcpc_dev);
- break;
-#endif /* CONFIG_USB_PD_VBUS_PRESENT_TOUT */
-
- case PD_PE_VDM_POSTPONE:
- tcpc_dev->pd_postpone_vdm_timeout = true;
- atomic_inc(&tcpc_dev->pending_event);
- wake_up_interruptible(&tcpc_dev->event_loop_wait_que);
- break;
-
- default:
- pd_put_event(tcpc_dev, &pd_event, false);
- break;
- }
-#endif
-
- tcpc_disable_timer(tcpc_dev, timer_id);
-}
-
-#define TCPC_TIMER_TRIGGER() do \
-{ \
- down(&tcpc_dev->timer_tick_lock); \
- rt_set_bit(index, (u64 *)&tcpc_dev->timer_tick); \
- up(&tcpc_dev->timer_tick_lock); \
- wake_up_interruptible(&tcpc_dev->timer_wait_que); \
-} while (0)
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-static enum hrtimer_restart tcpc_timer_bist_cont_mode(struct hrtimer *timer)
-{
- int index = PD_TIMER_BIST_CONT_MODE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_discover_id(struct hrtimer *timer)
-{
- int index = PD_TIMER_DISCOVER_ID;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_hard_reset_complete(
- struct hrtimer *timer)
-{
- int index = PD_TIMER_HARD_RESET_COMPLETE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_no_response(struct hrtimer *timer)
-{
- int index = PD_TIMER_NO_RESPONSE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_ps_hard_reset(struct hrtimer *timer)
-{
- int index = PD_TIMER_PS_HARD_RESET;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_ps_source_off(struct hrtimer *timer)
-{
- int index = PD_TIMER_PS_SOURCE_OFF;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_ps_source_on(struct hrtimer *timer)
-{
- int index = PD_TIMER_PS_SOURCE_ON;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_ps_transition(struct hrtimer *timer)
-{
- int index = PD_TIMER_PS_TRANSITION;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_sender_response(struct hrtimer *timer)
-{
- int index = PD_TIMER_SENDER_RESPONSE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_sink_activity(struct hrtimer *timer)
-{
- int index = PD_TIMER_SINK_ACTIVITY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_sink_request(struct hrtimer *timer)
-{
- int index = PD_TIMER_SINK_REQUEST;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_sink_wait_cap(struct hrtimer *timer)
-{
- int index = PD_TIMER_SINK_WAIT_CAP;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_source_activity(struct hrtimer *timer)
-{
- int index = PD_TIMER_SOURCE_ACTIVITY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_source_capability(struct hrtimer *timer)
-{
- int index = PD_TIMER_SOURCE_CAPABILITY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_source_start(struct hrtimer *timer)
-{
- int index = PD_TIMER_SOURCE_START;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vconn_on(struct hrtimer *timer)
-{
- int index = PD_TIMER_VCONN_ON;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vdm_mode_entry(struct hrtimer *timer)
-{
- int index = PD_TIMER_VDM_MODE_ENTRY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vdm_mode_exit(struct hrtimer *timer)
-{
- int index = PD_TIMER_VDM_MODE_EXIT;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vdm_response(struct hrtimer *timer)
-{
- int index = PD_TIMER_VDM_RESPONSE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_source_transition(struct hrtimer *timer)
-{
- int index = PD_TIMER_SOURCE_TRANSITION;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_src_recover(struct hrtimer *timer)
-{
- int index = PD_TIMER_SRC_RECOVER;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vsafe0v_delay(struct hrtimer *timer)
-{
- int index = PD_TIMER_VSAFE0V_DELAY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vsafe0v_tout(struct hrtimer *timer)
-{
- int index = PD_TIMER_VSAFE0V_TOUT;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_error_recovery(struct hrtimer *timer)
-{
- int index = TYPEC_TIMER_ERROR_RECOVERY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_pd_discard(struct hrtimer *timer)
-{
- int index = PD_TIMER_DISCARD;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vbus_stable(struct hrtimer *timer)
-{
- int index = PD_TIMER_VBUS_STABLE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_vbus_present(struct hrtimer *timer)
-{
- int index = PD_TIMER_VBUS_PRESENT;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart pd_pe_vdm_postpone_timeout(struct hrtimer *timer)
-{
- int index = PD_PE_VDM_POSTPONE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_rt_pe_idle(struct hrtimer *timer)
-{
- int index = TYPEC_RT_TIMER_PE_IDLE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-static enum hrtimer_restart tcpc_timer_rt_vsafe0v_delay(struct hrtimer *timer)
-{
- int index = TYPEC_RT_TIMER_SAFE0V_DELAY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_rt_vsafe0v_tout(struct hrtimer *timer)
-{
- int index = TYPEC_RT_TIMER_SAFE0V_TOUT;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_try_drp_try(struct hrtimer *timer)
-{
- int index = TYPEC_TRY_TIMER_DRP_TRY;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_try_drp_trywait(struct hrtimer *timer)
-{
- int index = TYPEC_TRY_TIMER_DRP_TRYWAIT;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_ccdebounce(struct hrtimer *timer)
-{
- int index = TYPEC_TIMER_CCDEBOUNCE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_pddebounce(struct hrtimer *timer)
-{
- int index = TYPEC_TIMER_PDDEBOUNCE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_wakeup(struct hrtimer *timer)
-{
- int index = TYPEC_TIMER_WAKEUP;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static enum hrtimer_restart tcpc_timer_drp_src_toggle(struct hrtimer *timer)
-{
- int index = TYPEC_TIMER_DRP_SRC_TOGGLE;
- struct tcpc_device *tcpc_dev =
- container_of(timer, struct tcpc_device, tcpc_timer[index]);
-
- TCPC_TIMER_TRIGGER();
- return HRTIMER_NORESTART;
-}
-
-static tcpc_hrtimer_call tcpc_timer_call[PD_TIMER_NR] = {
-#ifdef CONFIG_USB_POWER_DELIVERY
- [PD_TIMER_BIST_CONT_MODE] = tcpc_timer_bist_cont_mode,
- [PD_TIMER_DISCOVER_ID] = tcpc_timer_discover_id,
- [PD_TIMER_HARD_RESET_COMPLETE] = tcpc_timer_hard_reset_complete,
- [PD_TIMER_NO_RESPONSE] = tcpc_timer_no_response,
- [PD_TIMER_PS_HARD_RESET] = tcpc_timer_ps_hard_reset,
- [PD_TIMER_PS_SOURCE_OFF] = tcpc_timer_ps_source_off,
- [PD_TIMER_PS_SOURCE_ON] = tcpc_timer_ps_source_on,
- [PD_TIMER_PS_TRANSITION] = tcpc_timer_ps_transition,
- [PD_TIMER_SENDER_RESPONSE] = tcpc_timer_sender_response,
- [PD_TIMER_SINK_ACTIVITY] = tcpc_timer_sink_activity,
- [PD_TIMER_SINK_REQUEST] = tcpc_timer_sink_request,
- [PD_TIMER_SINK_WAIT_CAP] = tcpc_timer_sink_wait_cap,
- [PD_TIMER_SOURCE_ACTIVITY] = tcpc_timer_source_activity,
- [PD_TIMER_SOURCE_CAPABILITY] = tcpc_timer_source_capability,
- [PD_TIMER_SOURCE_START] = tcpc_timer_source_start,
- [PD_TIMER_VCONN_ON] = tcpc_timer_vconn_on,
- [PD_TIMER_VDM_MODE_ENTRY] = tcpc_timer_vdm_mode_entry,
- [PD_TIMER_VDM_MODE_EXIT] = tcpc_timer_vdm_mode_exit,
- [PD_TIMER_VDM_RESPONSE] = tcpc_timer_vdm_response,
- [PD_TIMER_SOURCE_TRANSITION] = tcpc_timer_source_transition,
- [PD_TIMER_SRC_RECOVER] = tcpc_timer_src_recover,
- [PD_TIMER_VSAFE0V_DELAY] = tcpc_timer_vsafe0v_delay,
- [PD_TIMER_VSAFE0V_TOUT] = tcpc_timer_vsafe0v_tout,
- [PD_TIMER_DISCARD] = tcpc_timer_pd_discard,
- [PD_TIMER_VBUS_STABLE] = tcpc_timer_vbus_stable,
- [PD_TIMER_VBUS_PRESENT] = tcpc_timer_vbus_present,
- [PD_PE_VDM_POSTPONE] = pd_pe_vdm_postpone_timeout,
-
- [TYPEC_RT_TIMER_PE_IDLE] = tcpc_timer_rt_pe_idle,
- [TYPEC_RT_TIMER_SAFE0V_DELAY] = tcpc_timer_rt_vsafe0v_delay,
- [TYPEC_RT_TIMER_SAFE0V_TOUT] = tcpc_timer_rt_vsafe0v_tout,
-
- [TYPEC_TRY_TIMER_DRP_TRY] = tcpc_timer_try_drp_try,
- [TYPEC_TRY_TIMER_DRP_TRYWAIT] = tcpc_timer_try_drp_trywait,
-
- [TYPEC_TIMER_CCDEBOUNCE] = tcpc_timer_ccdebounce,
- [TYPEC_TIMER_PDDEBOUNCE] = tcpc_timer_pddebounce,
- [TYPEC_TIMER_ERROR_RECOVERY] = tcpc_timer_error_recovery,
- [TYPEC_TIMER_WAKEUP] = tcpc_timer_wakeup,
- [TYPEC_TIMER_DRP_SRC_TOGGLE] = tcpc_timer_drp_src_toggle,
-#else
- [TYPEC_RT_TIMER_SAFE0V_DELAY] = tcpc_timer_rt_vsafe0v_delay,
- [TYPEC_RT_TIMER_SAFE0V_TOUT] = tcpc_timer_rt_vsafe0v_tout,
-
- [TYPEC_TRY_TIMER_DRP_TRY] = tcpc_timer_try_drp_try,
- [TYPEC_TRY_TIMER_DRP_TRYWAIT] = tcpc_timer_try_drp_trywait,
-
- [TYPEC_TIMER_CCDEBOUNCE] = tcpc_timer_ccdebounce,
- [TYPEC_TIMER_PDDEBOUNCE] = tcpc_timer_pddebounce,
- [TYPEC_TIMER_WAKEUP] = tcpc_timer_wakup,
- [TYPEC_TIMER_DRP_SRC_TOGGLE] = tcpc_timer_drp_src_toggle,
-#endif /* CONFIG_USB_POWER_DELIVERY */
-};
-
-/*
- * [BLOCK] Control Timer
- */
-
-static inline void tcpc_reset_timer_range(
- struct tcpc_device *tcpc, int start, int end)
-{
- int i;
- u64 mask;
-
- down(&tcpc->timer_enable_mask_lock);
- mask = rt_get_value((u64 *)&tcpc->timer_enable_mask);
- up(&tcpc->timer_enable_mask_lock);
-
- for (i = start; i <= end; i++) {
- if (mask & (((u64)1) << i)) {
- hrtimer_try_to_cancel(&tcpc->tcpc_timer[i]);
- down(&tcpc->timer_enable_mask_lock);
- rt_clear_bit(i, (u64 *)&tcpc->timer_enable_mask);
- up(&tcpc->timer_enable_mask_lock);
- }
- }
-}
-
-void tcpc_restart_timer(struct tcpc_device *tcpc, u32 timer_id)
-{
- u64 mask;
-
- down(&tcpc->timer_enable_mask_lock);
- mask = rt_get_value((u64 *)&tcpc->timer_enable_mask);
- up(&tcpc->timer_enable_mask_lock);
- if (mask & (((u64)1) << timer_id))
- tcpc_disable_timer(tcpc, timer_id);
- tcpc_enable_timer(tcpc, timer_id);
-}
-
-void tcpc_enable_timer(struct tcpc_device *tcpc, u32 timer_id)
-{
- u32 r, mod;
- char buf[1024] = { 0 };
-
- TCPC_TIMER_EN_DBG(tcpc, timer_id);
- if (timer_id >= PD_TIMER_NR)
- snprintf(buf, sizeof(buf),
- "the timer_id %d is over PD_TIMER_NR\n",
- timer_id);
- mutex_lock(&tcpc->timer_lock);
- if (timer_id >= TYPEC_TIMER_START_ID)
- tcpc_reset_timer_range(tcpc, TYPEC_TIMER_START_ID, PD_TIMER_NR);
-
- down(&tcpc->timer_enable_mask_lock);
- rt_set_bit(timer_id, (u64 *)&tcpc->timer_enable_mask);
- up(&tcpc->timer_enable_mask_lock);
- r = tcpc_timer_timeout[timer_id] / 1000000;
- mod = tcpc_timer_timeout[timer_id] % 1000000;
-
- mutex_unlock(&tcpc->timer_lock);
- hrtimer_start(&tcpc->tcpc_timer[timer_id],
- ktime_set(r, mod * 1000), HRTIMER_MODE_REL);
-}
-
-void tcpc_disable_timer(struct tcpc_device *tcpc_dev, u32 timer_id)
-{
- u64 mask;
- char buf[1024] = { 0 };
-
- down(&tcpc_dev->timer_enable_mask_lock);
- mask = rt_get_value((u64 *)&tcpc_dev->timer_enable_mask);
- up(&tcpc_dev->timer_enable_mask_lock);
-
- if (timer_id >= PD_TIMER_NR) {
- snprintf(buf, sizeof(buf),
- "the timer_id %d is over PD_TIMER_NR\n",
- timer_id);
- }
- if (mask & (((u64)1) << timer_id)) {
- hrtimer_try_to_cancel(&tcpc_dev->tcpc_timer[timer_id]);
- rt_clear_bit(timer_id,
- (u64 *)&tcpc_dev->timer_enable_mask);
- }
-}
-
-void tcpc_timer_reset(struct tcpc_device *tcpc_dev)
-{
- u64 mask;
- int i;
-
- down(&tcpc_dev->timer_enable_mask_lock);
- mask = rt_get_value((u64 *)&tcpc_dev->timer_enable_mask);
- up(&tcpc_dev->timer_enable_mask_lock);
- for (i = 0; i < PD_TIMER_NR; i++)
- if (mask & (((u64)1) << i))
- hrtimer_try_to_cancel(&tcpc_dev->tcpc_timer[i]);
- rt_set_value((u64 *)&tcpc_dev->timer_enable_mask, 0);
-}
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-void tcpc_reset_pe_timer(struct tcpc_device *tcpc_dev)
-{
- mutex_lock(&tcpc_dev->timer_lock);
- tcpc_reset_timer_range(tcpc_dev, 0, PD_PE_TIMER_END_ID);
- mutex_unlock(&tcpc_dev->timer_lock);
-}
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-void tcpc_reset_typec_debounce_timer(struct tcpc_device *tcpc)
-{
- mutex_lock(&tcpc->timer_lock);
- tcpc_reset_timer_range(tcpc, TYPEC_TIMER_START_ID, PD_TIMER_NR);
- mutex_unlock(&tcpc->timer_lock);
-}
-
-void tcpc_reset_typec_try_timer(struct tcpc_device *tcpc)
-{
- mutex_lock(&tcpc->timer_lock);
- tcpc_reset_timer_range(tcpc,
- TYPEC_TRY_TIMER_START_ID, TYPEC_TIMER_START_ID);
- mutex_unlock(&tcpc->timer_lock);
-}
-
-static void tcpc_handle_timer_triggered(struct tcpc_device *tcpc_dev)
-{
- u64 triggered_timer;
- int i = 0;
-
- down(&tcpc_dev->timer_tick_lock);
- triggered_timer = rt_get_value((u64 *)&tcpc_dev->timer_tick);
- up(&tcpc_dev->timer_tick_lock);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- for (i = 0; i < PD_PE_TIMER_END_ID; i++) {
- if (triggered_timer & RT_MASK64(i)) {
- TCPC_TIMER_DBG(tcpc_dev, i);
- on_pe_timer_timeout(tcpc_dev, i);
- down(&tcpc_dev->timer_tick_lock);
- rt_clear_bit(i, (u64 *)&tcpc_dev->timer_tick);
- up(&tcpc_dev->timer_tick_lock);
- }
- }
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- mutex_lock(&tcpc_dev->typec_lock);
- for (; i < PD_TIMER_NR; i++) {
- if (triggered_timer & RT_MASK64(i)) {
- TCPC_TIMER_DBG(tcpc_dev, i);
- tcpc_typec_handle_timeout(tcpc_dev, i);
- down(&tcpc_dev->timer_tick_lock);
- rt_clear_bit(i, (u64 *)&tcpc_dev->timer_tick);
- up(&tcpc_dev->timer_tick_lock);
- }
- }
- mutex_unlock(&tcpc_dev->typec_lock);
-}
-
-static int tcpc_timer_thread(void *param)
-{
- struct tcpc_device *tcpc_dev = param;
-
- u64 *timer_tick;
- struct sched_param sch_param = {.sched_priority = MAX_RT_PRIO - 1};
-
- down(&tcpc_dev->timer_tick_lock);
- timer_tick = &tcpc_dev->timer_tick;
- up(&tcpc_dev->timer_tick_lock);
-
- sched_setscheduler(current, SCHED_FIFO, &sch_param);
- while (true) {
- wait_event_interruptible(tcpc_dev->timer_wait_que,
- ((*timer_tick) ? true : false) |
- tcpc_dev->timer_thead_stop);
- if (kthread_should_stop() || tcpc_dev->timer_thead_stop)
- break;
- do {
- tcpc_handle_timer_triggered(tcpc_dev);
- } while (*timer_tick);
- }
- return 0;
-}
-
-int tcpci_timer_init(struct tcpc_device *tcpc_dev)
-{
- int i;
-
- pr_info("PD Timer number = %d\n", PD_TIMER_NR);
- tcpc_dev->timer_task = kthread_create(tcpc_timer_thread, tcpc_dev,
- "tcpc_timer_%s.%p", dev_name(&tcpc_dev->dev), tcpc_dev);
- init_waitqueue_head(&tcpc_dev->timer_wait_que);
- down(&tcpc_dev->timer_tick_lock);
- tcpc_dev->timer_tick = 0;
- up(&tcpc_dev->timer_tick_lock);
- rt_set_value((u64 *)&tcpc_dev->timer_enable_mask, 0);
- wake_up_process(tcpc_dev->timer_task);
- for (i = 0; i < PD_TIMER_NR; i++) {
- hrtimer_init(&tcpc_dev->tcpc_timer[i],
- CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- tcpc_dev->tcpc_timer[i].function = tcpc_timer_call[i];
- }
-
- pr_info("%s : init OK\n", __func__);
- return 0;
-}
-
-int tcpci_timer_deinit(struct tcpc_device *tcpc_dev)
-{
- u64 mask;
- int i;
-
- down(&tcpc_dev->timer_enable_mask_lock);
- mask = rt_get_value((u64 *)&tcpc_dev->timer_enable_mask);
- up(&tcpc_dev->timer_enable_mask_lock);
-
- mutex_lock(&tcpc_dev->timer_lock);
- wake_up_interruptible(&tcpc_dev->timer_wait_que);
- kthread_stop(tcpc_dev->timer_task);
- for (i = 0; i < PD_TIMER_NR; i++) {
- if (mask & (1 << i))
- hrtimer_try_to_cancel(&tcpc_dev->tcpc_timer[i]);
- }
-
- pr_info("%s : de init OK\n", __func__);
- mutex_unlock(&tcpc_dev->timer_lock);
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * TCPC Type-C Driver for Richtek
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-#include <linux/cpu.h>
-
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_timer.h>
-#include <linux/hisi/usb/hub/hisi_hub.h>
-#include <linux/hisi/log/hisi_log.h>
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
-#define CONFIG_TYPEC_CAP_TRY_STATE
-#endif
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
-#undef CONFIG_TYPEC_CAP_TRY_STATE
-#define CONFIG_TYPEC_CAP_TRY_STATE
-#endif
-
-enum TYPEC_WAIT_PS_STATE {
- TYPEC_WAIT_PS_DISABLE = 0,
- TYPEC_WAIT_PS_SNK_VSAFE5V,
- TYPEC_WAIT_PS_SRC_VSAFE0V,
- TYPEC_WAIT_PS_SRC_VSAFE5V,
-};
-
-#if TYPEC_DBG_ENABLE
-static const char *const typec_wait_ps_name[] = {
- "Disable",
- "SNK_VSafe5V",
- "SRC_VSafe0V",
- "SRC_VSafe5V",
-};
-#endif /* TYPEC_DBG_ENABLE */
-
-enum TYPEC_HOST_OR_DEVICE {
- TYPEC_INIT = 0,
- TYPEC_HOST,
- TYPEC_DEVICE
-};
-
-static int oldstatus = TYPEC_INIT;
-
-static inline void typec_wait_ps_change(struct tcpc_device *tcpc_dev,
- enum TYPEC_WAIT_PS_STATE state)
-{
-#if TYPEC_DBG_ENABLE
- u8 old_state;
- u8 new_state = (u8)state;
-
- old_state = tcpc_dev->typec_wait_ps_change;
- if (new_state != old_state)
- TYPEC_DBG("wait_ps=%s\r\n", typec_wait_ps_name[new_state]);
-#endif
- hisilog_err("%s: typec_wait_ps_change!!!+++++++++++\n", __func__);
-
-#ifdef CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT
- if (state == TYPEC_WAIT_PS_SRC_VSAFE0V)
- tcpc_enable_timer(tcpc_dev, TYPEC_RT_TIMER_SAFE0V_TOUT);
-#endif /* CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT */
-
- if (tcpc_dev->typec_wait_ps_change == TYPEC_WAIT_PS_SRC_VSAFE0V &&
- state != TYPEC_WAIT_PS_SRC_VSAFE0V) {
- tcpc_disable_timer(tcpc_dev, TYPEC_RT_TIMER_SAFE0V_DELAY);
-
-#ifdef CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT
- tcpc_disable_timer(tcpc_dev, TYPEC_RT_TIMER_SAFE0V_TOUT);
-#endif /* CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT */
- }
-
- tcpc_dev->typec_wait_ps_change = (u8)state;
- hisilog_err("%s: typec_wait_ps_change!!!-----------\n", __func__);
-}
-
-/* #define TYPEC_EXIT_ATTACHED_SRC_NO_DEBOUNCE */
-#define TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS
-
-static inline int typec_enable_low_power_mode(
- struct tcpc_device *tcpc_dev, int pull);
-
-#define typec_get_cc1() \
- tcpc_dev->typec_remote_cc[0]
-#define typec_get_cc2() \
- tcpc_dev->typec_remote_cc[1]
-#define typec_get_cc_res() \
- (tcpc_dev->typec_polarity ? typec_get_cc2() : typec_get_cc1())
-
-#define typec_check_cc1(cc) \
- (typec_get_cc1() == (cc))
-
-#define typec_check_cc2(cc) \
- (typec_get_cc2() == (cc))
-
-#define typec_check_cc(cc1, cc2) \
- (typec_check_cc1(cc1) && typec_check_cc2(cc2))
-
-#define typec_check_cc1_unequal(cc) \
- (typec_get_cc1() != (cc))
-
-#define typec_check_cc2_unequal(cc) \
- (typec_get_cc2() != (cc))
-
-#define typec_check_cc_unequal(cc1, cc2) \
- (typec_check_cc1_unequal(cc1) && typec_check_cc2_unequal(cc2))
-
-#define typec_is_drp_toggling() \
- (typec_get_cc1() == TYPEC_CC_DRP_TOGGLING)
-
-#define typec_is_cc_open() \
- typec_check_cc(TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_OPEN)
-
-/* TYPEC_GET_CC_STATUS */
-
-/*
- * [BLOCK] TYPEC Connection State Definition
- */
-
-enum TYPEC_CONNECTION_STATE {
- typec_disabled = 0,
- typec_errorrecovery,
-
- typec_unattached_snk,
- typec_unattached_src,
-
- typec_attachwait_snk,
- typec_attachwait_src,
-
- typec_attached_snk,
- typec_attached_src,
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- /* Require : Assert Rp
- * Exit(-> Attached.SRC) : Detect Rd (tPDDebounce).
- * Exit(-> TryWait.SNK) : Not detect Rd after tDRPTry
- */
- typec_try_src,
-
- /* Require : Assert Rd
- * Exit(-> Attached.SNK) : Detect Rp (tCCDebounce) and Vbus present.
- * Exit(-> Unattached.SNK) : Not detect Rp (tPDDebounce)
- */
-
- typec_trywait_snk,
- typec_trywait_snk_pe,
-#endif
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
-
- /* Require : Assert Rd
- * Wait for tDRPTry and only then begin monitoring CC.
- * Exit (-> Attached.SNK) : Detect Rp (tPDDebounce) and Vbus present.
- * Exit (-> TryWait.SRC) : Not detect Rp for tPDDebounce.
- */
- typec_try_snk,
-
- /*
- * Require : Assert Rp
- * Exit (-> Attached.SRC) : Detect Rd (tCCDebounce)
- * Exit (-> Unattached.SNK) : Not detect Rd after tDRPTry
- */
-
- typec_trywait_src,
- typec_trywait_src_pe,
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
- typec_audioaccessory,
- typec_debugaccessory,
-
-#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
- typec_attached_dbgacc_snk,
-#endif /* CONFIG_TYPEC_CAP_DBGACC_SNK */
-
-#ifdef CONFIG_TYPEC_CAP_CUSTOM_SRC
- typec_attached_custom_src,
-#endif /* CONFIG_TYPEC_CAP_CUSTOM_SRC */
-
- typec_unattachwait_pe, /* Wait Policy Engine go to Idle */
-};
-
-static const char *const typec_state_name[] = {
- "Disabled",
- "ErrorRecovery",
-
- "Unattached.SNK",
- "Unattached.SRC",
-
- "AttachWait.SNK",
- "AttachWait.SRC",
-
- "Attached.SNK",
- "Attached.SRC",
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- "Try.SRC",
- "TryWait.SNK",
- "TryWait.SNK.PE",
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- "Try.SNK",
- "TryWait.SRC",
- "TryWait.SRC.PE",
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
- "AudioAccessory",
- "DebugAccessory",
-
-#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
- "DBGACC.SNK",
-#endif /* CONFIG_TYPEC_CAP_DBGACC_SNK */
-
-#ifdef CONFIG_TYPEC_CAP_CUSTOM_SRC
- "Custom.SRC",
-#endif /* CONFIG_TYPEC_CAP_CUSTOM_SRC */
-
- "UnattachWait.PE",
-};
-
-static inline void typec_transfer_state(struct tcpc_device *tcpc_dev,
- enum TYPEC_CONNECTION_STATE state)
-{
- TYPEC_INFO("** %s\r\n", typec_state_name[state]);
- tcpc_dev->typec_state = (u8)state;
-}
-
-#define TYPEC_NEW_STATE(state) \
- (typec_transfer_state(tcpc_dev, state))
-
-/*
- * [BLOCK] TypeC Alert Attach Status Changed
- */
-
-static const char *const typec_attach_name[] = {
- "NULL",
- "SINK",
- "SOURCE",
- "AUDIO",
- "DEBUG",
-
-#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
- "DBGACC_SNK",
-#endif /* CONFIG_TYPEC_CAP_DBGACC_SNK */
-
-#ifdef CONFIG_TYPEC_CAP_CUSTOM_SRC
- "CUSTOM_SRC",
-#endif /* CONFIG_TYPEC_CAP_CUSTOM_SRC */
-};
-
-static int typec_alert_attach_state_change(struct tcpc_device *tcpc_dev)
-{
- int ret = 0;
-
- if (tcpc_dev->typec_attach_old == tcpc_dev->typec_attach_new) {
- TYPEC_DBG("Attached-> %s(repeat)\r\n",
- typec_attach_name[tcpc_dev->typec_attach_new]);
- return 0;
- }
-
- TYPEC_INFO("Attached-> %s\r\n",
- typec_attach_name[tcpc_dev->typec_attach_new]);
-
- /*Report function */
- ret = tcpci_report_usb_port_changed(tcpc_dev);
-
- tcpc_dev->typec_attach_old = tcpc_dev->typec_attach_new;
- return ret;
-}
-
-/*
- * [BLOCK] Unattached Entry
- */
-
-static inline int typec_enable_low_power_mode(
- struct tcpc_device *tcpc_dev, int pull)
-{
- int ret = 0;
-
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- if (tcpc_dev->typec_legacy_cable) {
- TYPEC_DBG("LPM_LCOnly\r\n");
- return 0;
- }
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
- if (tcpc_dev->typec_cable_only) {
- TYPEC_DBG("LPM_RaOnly\r\n");
-
-#ifdef CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG
- if (tcpc_dev->tcpc_flags & TCPC_FLAGS_LPM_WAKEUP_WATCHDOG)
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_WAKEUP);
-#endif /* CONFIG_TYPEC_CAP_LPM_WAKEUP_WATCHDOG */
-
- return 0;
- }
-
- if (!tcpc_dev->typec_lpm)
- ret = tcpci_set_low_power_mode(tcpc_dev, true, pull);
-
- tcpc_dev->typec_lpm = true;
- return ret;
-}
-
-static inline int typec_disable_low_power_mode(
- struct tcpc_device *tcpc_dev)
-{
- int ret = 0;
-
- if (tcpc_dev->typec_lpm)
- ret = tcpci_set_low_power_mode(tcpc_dev, false, TYPEC_CC_DRP);
-
- tcpc_dev->typec_lpm = false;
- return ret;
-}
-
-static void typec_unattached_power_entry(struct tcpc_device *tcpc_dev)
-{
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
- hisilog_err("%s:!!!+++++++++++\n",
- __func__);
-
- if (tcpc_dev->typec_power_ctrl) {
- tcpc_dev->typec_power_ctrl = false;
- tcpci_set_vconn(tcpc_dev, false);
- tcpci_disable_vbus_control(tcpc_dev);
- }
- hisilog_err("%s:!!!-----------\n",
- __func__);
-}
-
-static void typec_unattached_entry(struct tcpc_device *tcpc_dev)
-{
- typec_unattached_power_entry(tcpc_dev);
-
- switch (tcpc_dev->typec_role) {
- case TYPEC_ROLE_SNK:
- TYPEC_NEW_STATE(typec_unattached_snk);
- TYPEC_DBG("TYPEC_ROLE_SNK\r\n");
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
- typec_enable_low_power_mode(tcpc_dev, TYPEC_CC_RD);
- break;
- case TYPEC_ROLE_SRC:
- TYPEC_NEW_STATE(typec_unattached_src);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP);
- typec_enable_low_power_mode(tcpc_dev, TYPEC_CC_RP);
- break;
- default:
- switch (tcpc_dev->typec_state) {
- case typec_attachwait_snk:
- case typec_audioaccessory:
- TYPEC_NEW_STATE(typec_unattached_src);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP);
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_DRP_SRC_TOGGLE);
- break;
- default:
- gpio_hub_switch_to_hub();
- gpio_hub_typec_power_off();
- if (oldstatus == TYPEC_DEVICE) {
- TYPEC_DBG("device off, otg host:%d:%d\r\n",
- oldstatus, tcpc_dev->typec_state);
- gpio_hub_power_on();
-
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- hisi_usb_otg_event(ID_FALL_EVENT);
- oldstatus = TYPEC_HOST;
- } else if (oldstatus == TYPEC_INIT) {
- TYPEC_DBG("init otg host no insert.\r\n");
- gpio_hub_power_on();
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- hisi_usb_otg_event(ID_FALL_EVENT);
- oldstatus = TYPEC_HOST;
- } else {
- TYPEC_DBG("host off, otg host:%d:%d\r\n",
- oldstatus, tcpc_dev->typec_state);
- }
- TYPEC_NEW_STATE(typec_unattached_snk);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_DRP);
- typec_enable_low_power_mode(tcpc_dev, TYPEC_CC_DRP);
- break;
- }
- break;
- }
-}
-
-static void typec_unattach_wait_pe_idle_entry(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->typec_attach_new = TYPEC_UNATTACHED;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->typec_attach_old) {
- TYPEC_NEW_STATE(typec_unattachwait_pe);
- return;
- }
-#endif
-
- typec_unattached_entry(tcpc_dev);
-}
-
-/*
- * [BLOCK] Attached Entry
- */
-
-static inline int typec_set_polarity(struct tcpc_device *tcpc_dev,
- bool polarity)
-{
- tcpc_dev->typec_polarity = polarity;
- return tcpci_set_polarity(tcpc_dev, polarity);
-}
-
-static inline int typec_set_plug_orient(struct tcpc_device *tcpc_dev,
- u8 res, bool polarity)
-{
- int rv = typec_set_polarity(tcpc_dev, polarity);
-
- if (rv)
- return rv;
-
- return tcpci_set_cc(tcpc_dev, res);
-}
-
-static void typec_source_attached_with_vbus_entry(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_SRC;
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-}
-
-static inline void typec_source_attached_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_attached_src);
-
- TYPEC_DBG("typec otg host attach %s\r\n", __func__);
- oldstatus = TYPEC_HOST;
- gpio_hub_switch_to_typec();
- gpio_hub_typec_power_on();
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_SRC_VSAFE5V);
-
- tcpc_disable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-
- typec_set_plug_orient(tcpc_dev,
- tcpc_dev->typec_local_rp_level,
- typec_check_cc2(TYPEC_CC_VOLT_RD));
-
- tcpc_dev->typec_power_ctrl = true;
- tcpci_set_vconn(tcpc_dev, true);
- tcpci_source_vbus(tcpc_dev,
- TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_5V, -1);
-}
-
-static inline void typec_sink_attached_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_attached_snk);
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- tcpc_dev->typec_legacy_cable = false;
- tcpc_dev->typec_legacy_cable_suspect = 0;
-#endif /* CONFIG_TYPEC_CHECK_LEGAY_CABLE */
-
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_SNK;
-
-#ifdef CONFIG_TYPEC_CAP_TRY_STATE
- if (tcpc_dev->typec_role >= TYPEC_ROLE_DRP)
- tcpc_reset_typec_try_timer(tcpc_dev);
-#endif /* CONFIG_TYPEC_CAP_TRY_STATE */
-
- typec_set_plug_orient(tcpc_dev, TYPEC_CC_RD,
- typec_check_cc2_unequal(TYPEC_CC_VOLT_OPEN));
- tcpc_dev->typec_remote_rp_level = typec_get_cc_res();
-
- tcpc_dev->typec_power_ctrl = true;
- tcpci_sink_vbus(tcpc_dev, TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SINK_5V, -1);
-}
-
-static inline void typec_custom_src_attached_entry(
- struct tcpc_device *tcpc_dev)
-{
-#ifdef CONFIG_TYPEC_CAP_CUSTOM_SRC
- int cc1 = typec_get_cc1();
- int cc2 = typec_get_cc2();
-
- if (cc1 == TYPEC_CC_VOLT_SNK_DFT && cc2 == TYPEC_CC_VOLT_SNK_DFT) {
- TYPEC_NEW_STATE(typec_attached_custom_src);
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_CUSTOM_SRC;
- TYPEC_DBG("typec host mode, device attached\r\n");
- oldstatus = TYPEC_DEVICE;
- gpio_hub_power_off();
- gpio_hub_typec_power_off();
-
- hisi_usb_otg_event(ID_RISE_EVENT);
- hisi_usb_otg_event(CHARGER_CONNECT_EVENT);
- return;
- }
-#endif /* CONFIG_TYPEC_CAP_CUSTOM_SRC */
-
-#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
- TYPEC_DBG("[Warning] Same Rp (%d)\r\n", cc1);
-#else
- TYPEC_DBG("[Warning] CC Both Rp\r\n");
-#endif
-}
-
-#ifdef CONFIG_TYPEC_CAP_DBGACC_SNK
-
-static inline u8 typec_get_sink_dbg_acc_rp_level(
- int cc1, int cc2)
-{
- if (cc2 == TYPEC_CC_VOLT_SNK_DFT)
- return cc1;
- else
- return TYPEC_CC_VOLT_SNK_DFT;
-}
-
-static inline void typec_sink_dbg_acc_attached_entry(
- struct tcpc_device *tcpc_dev)
-{
- bool polarity;
- u8 rp_level;
-
- int cc1 = typec_get_cc1();
- int cc2 = typec_get_cc2();
-
- if (cc1 == cc2) {
- typec_custom_src_attached_entry(tcpc_dev);
- return;
- }
-
- TYPEC_NEW_STATE(typec_attached_dbgacc_snk);
-
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_DBGACC_SNK;
-
- polarity = cc2 > cc1;
-
- if (polarity)
- rp_level = typec_get_sink_dbg_acc_rp_level(cc2, cc1);
- else
- rp_level = typec_get_sink_dbg_acc_rp_level(cc1, cc2);
-
- typec_set_plug_orient(tcpc_dev, TYPEC_CC_RD, polarity);
- tcpc_dev->typec_remote_rp_level = rp_level;
-
- tcpc_dev->typec_power_ctrl = true;
- tcpci_sink_vbus(tcpc_dev, TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SINK_5V, -1);
-}
-#else
-static inline void typec_sink_dbg_acc_attached_entry(
- struct tcpc_device *tcpc_dev)
-{
- typec_custom_src_attached_entry(tcpc_dev);
-}
-#endif /* CONFIG_TYPEC_CAP_DBGACC_SNK */
-
-/*
- * [BLOCK] Try.SRC / TryWait.SNK
- */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
-
-static inline void typec_try_src_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_try_src);
- tcpc_dev->typec_drp_try_timeout = false;
-
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP);
- tcpc_enable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-}
-
-static inline void typec_trywait_snk_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_trywait_snk);
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
- tcpci_set_vconn(tcpc_dev, false);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
- tcpci_source_vbus(tcpc_dev,
- TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_0V, 0);
- tcpc_disable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
-}
-
-static inline void typec_trywait_snk_pe_entry(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->typec_attach_new = TYPEC_UNATTACHED;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->typec_attach_old) {
- TYPEC_NEW_STATE(typec_trywait_snk_pe);
- return;
- }
-#endif
-
- typec_trywait_snk_entry(tcpc_dev);
-}
-
-#endif /* #ifdef CONFIG_TYPEC_CAP_TRY_SOURCE */
-
-/*
- * [BLOCK] Try.SNK / TryWait.SRC
- */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
-
-static inline void typec_try_snk_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_try_snk);
- tcpc_dev->typec_drp_try_timeout = false;
-
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
- tcpc_enable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-}
-
-static inline void typec_trywait_src_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_NEW_STATE(typec_trywait_src);
- tcpc_dev->typec_drp_try_timeout = false;
-
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP);
- tcpci_sink_vbus(tcpc_dev, TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SINK_0V, 0);
- tcpc_enable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-}
-
-#ifndef CONFIG_USB_POWER_DELIVERY
-static inline void typec_trywait_src_pe_entry(struct tcpc_device *tcpc_dev)
-{
- tcpc_dev->typec_attach_new = TYPEC_UNATTACHED;
-
- if (tcpc_dev->typec_attach_old) {
- TYPEC_NEW_STATE(typec_trywait_src_pe);
- return;
- }
-
- typec_trywait_src_entry(tcpc_dev);
-}
-#endif
-
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
-/*
- * [BLOCK] Attach / Detach
- */
-
-static inline void typec_cc_snk_detect_vsafe5v_entry(
- struct tcpc_device *tcpc_dev)
-{
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
- if (typec_check_cc_unequal(TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_OPEN)) {
- typec_sink_dbg_acc_attached_entry(tcpc_dev);
- return;
- }
-
- TYPEC_DBG("typec device mode, attached\r\n");
- oldstatus = TYPEC_DEVICE;
- gpio_hub_power_off();
- gpio_hub_typec_power_off();
- hisi_usb_otg_event(ID_RISE_EVENT);
- gpio_hub_switch_to_typec();
- hisi_usb_otg_event(CHARGER_CONNECT_EVENT);
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- if (tcpc_dev->typec_role == TYPEC_ROLE_TRY_SRC) {
- if (tcpc_dev->typec_state == typec_attachwait_snk) {
- typec_try_src_entry(tcpc_dev);
- return;
- }
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
- typec_sink_attached_entry(tcpc_dev);
-}
-
-static inline void typec_cc_snk_detect_entry(struct tcpc_device *tcpc_dev)
-{
- /* If Port Partner act as Source without VBUS, wait vSafe5V */
- if (tcpci_check_vbus_valid(tcpc_dev))
- typec_cc_snk_detect_vsafe5v_entry(tcpc_dev);
- else
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_SNK_VSAFE5V);
-}
-
-static inline void typec_cc_src_detect_vsafe0v_entry(
- struct tcpc_device *tcpc_dev)
-{
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- if (tcpc_dev->typec_role == TYPEC_ROLE_TRY_SNK) {
- if (tcpc_dev->typec_state == typec_attachwait_src) {
- typec_try_snk_entry(tcpc_dev);
- return;
- }
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
- typec_source_attached_entry(tcpc_dev);
-}
-
-static inline void typec_cc_src_detect_entry(
- struct tcpc_device *tcpc_dev)
-{
- /* If Port Partner act as Sink with low VBUS, wait vSafe0v */
- bool vbus_absent = tcpci_check_vsafe0v(tcpc_dev, true);
-
- if (vbus_absent)
- typec_cc_src_detect_vsafe0v_entry(tcpc_dev);
- else
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_SRC_VSAFE0V);
-}
-
-static inline void typec_cc_src_remove_entry(struct tcpc_device *tcpc_dev)
-{
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- if (tcpc_dev->typec_role == TYPEC_ROLE_TRY_SRC) {
- switch (tcpc_dev->typec_state) {
- case typec_attached_src:
- typec_trywait_snk_pe_entry(tcpc_dev);
- return;
- case typec_try_src:
- typec_trywait_snk_entry(tcpc_dev);
- return;
- }
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
- typec_unattach_wait_pe_idle_entry(tcpc_dev);
-}
-
-static inline void typec_cc_snk_remove_entry(struct tcpc_device *tcpc_dev)
-{
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- if (tcpc_dev->typec_state == typec_try_snk) {
- typec_trywait_src_entry(tcpc_dev);
- return;
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
- typec_unattach_wait_pe_idle_entry(tcpc_dev);
-}
-
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
-
-static inline bool typec_check_legacy_cable(
- struct tcpc_device *tcpc_dev)
-{
- bool check_legacy = false;
-
- if (typec_check_cc(TYPEC_CC_VOLT_RD, TYPEC_CC_VOLT_OPEN) ||
- typec_check_cc(TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_RD))
- check_legacy = true;
-
- if (check_legacy &&
- tcpc_dev->typec_legacy_cable_suspect >=
- TCPC_LEGACY_CABLE_CONFIRM) {
- TYPEC_INFO("LC->Suspect\r\n");
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP_1_5);
- mdelay(1);
-
- if (tcpci_get_cc(tcpc_dev) != 0) {
- TYPEC_INFO("LC->Confirm\r\n");
- tcpc_dev->typec_legacy_cable = true;
- tcpc_dev->typec_legacy_cable_suspect =
- TCPC_LEGACY_CABLE_CONFIRM;
- return true;
- }
-
- tcpc_dev->typec_legacy_cable = false;
- tcpc_dev->typec_legacy_cable_suspect = 0;
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP);
- }
-
- return false;
-}
-
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
-static inline bool typec_cc_change_source_entry(struct tcpc_device *tcpc_dev)
-{
- int cc1, cc2;
-
- cc1 = typec_get_cc1();
- cc2 = typec_get_cc2();
-
- if ((cc1 == TYPEC_CC_VOLT_RD) && (cc2 == TYPEC_CC_VOLT_RD)) {
- TYPEC_NEW_STATE(typec_debugaccessory);
- TYPEC_DBG("[Debug] CC1&2 Both Rd\r\n");
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_DEBUG;
- } else if ((cc1 == TYPEC_CC_VOLT_RA) && (cc2 == TYPEC_CC_VOLT_RA)) {
- TYPEC_NEW_STATE(typec_audioaccessory);
- TYPEC_DBG("[Audio] CC1&2 Both Ra\r\n");
- tcpc_dev->typec_attach_new = TYPEC_ATTACHED_AUDIO;
- } else {
- if ((cc1 == TYPEC_CC_VOLT_RD) || (cc2 == TYPEC_CC_VOLT_RD)) {
- typec_cc_src_detect_entry(tcpc_dev);
- } else {
- if ((cc1 == TYPEC_CC_VOLT_RA) ||
- (cc2 == TYPEC_CC_VOLT_RA))
- TYPEC_DBG("[Cable] Ra Only\r\n");
- typec_cc_src_remove_entry(tcpc_dev);
- }
- }
-
- return true;
-}
-
-static inline bool typec_cc_change_sink_entry(struct tcpc_device *tcpc_dev)
-{
- if (typec_is_cc_open())
- typec_cc_snk_remove_entry(tcpc_dev);
- else
- typec_cc_snk_detect_entry(tcpc_dev);
-
- return true;
-}
-
-static inline bool typec_is_act_as_sink_role(
- struct tcpc_device *tcpc_dev)
-{
- bool as_sink = true;
- u8 cc_sum;
-
- switch (tcpc_dev->typec_local_cc & 0x07) {
- case TYPEC_CC_RP:
- as_sink = false;
- break;
- case TYPEC_CC_RD:
- as_sink = true;
- break;
- case TYPEC_CC_DRP:
- cc_sum = typec_get_cc1() + typec_get_cc2();
- as_sink = (cc_sum >= TYPEC_CC_VOLT_SNK_DFT);
- break;
- }
-
- return as_sink;
-}
-
-static inline bool typec_handle_cc_changed_entry(struct tcpc_device *tcpc_dev)
-{
- TYPEC_INFO("[CC_Change] %d/%d\r\n", typec_get_cc1(), typec_get_cc2());
-
- tcpc_dev->typec_attach_new = tcpc_dev->typec_attach_old;
-
- if (typec_is_act_as_sink_role(tcpc_dev))
- typec_cc_change_sink_entry(tcpc_dev);
- else
- typec_cc_change_source_entry(tcpc_dev);
-
- typec_alert_attach_state_change(tcpc_dev);
- return true;
-}
-
-/*
- * [BLOCK] Handle cc-change event
- */
-
-static inline void typec_attach_wait_entry(struct tcpc_device *tcpc_dev)
-{
- bool as_sink;
-
- if (tcpc_dev->typec_attach_old ||
- tcpc_dev->typec_state == typec_attached_src) {
- tcpc_reset_typec_debounce_timer(tcpc_dev);
- TYPEC_DBG("Attached, Ignore cc_attach\r\n");
- return;
- }
-
- switch (tcpc_dev->typec_state) {
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- case typec_try_src:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
- return;
-
- case typec_trywait_snk:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_CCDEBOUNCE);
- return;
-#endif
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- case typec_try_snk:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
- return;
-
- case typec_trywait_src:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_CCDEBOUNCE);
- return;
-#endif
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- case typec_unattachwait_pe:
- TYPEC_INFO("Force PE Idle\r\n");
- tcpc_dev->pd_wait_pe_idle = false;
- tcpc_disable_timer(tcpc_dev, TYPEC_RT_TIMER_PE_IDLE);
- typec_unattached_power_entry(tcpc_dev);
- break;
-#endif
- }
-
- as_sink = typec_is_act_as_sink_role(tcpc_dev);
-
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- if (!as_sink && typec_check_legacy_cable(tcpc_dev))
- return;
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
- if (as_sink)
- TYPEC_NEW_STATE(typec_attachwait_snk);
- else
- TYPEC_NEW_STATE(typec_attachwait_src);
-
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_CCDEBOUNCE);
-}
-
-#ifdef TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS
-static inline int typec_attached_snk_cc_detach(struct tcpc_device *tcpc_dev)
-{
- int vbus_valid = tcpci_check_vbus_valid(tcpc_dev);
- bool detach_by_cc = false;
-
- /* For Ellisys Test, Applying Low VBUS (3.67v) as Sink */
- if (vbus_valid) {
- detach_by_cc = true;
- TYPEC_DBG("Detach_CC (LowVBUS)\r\n");
- }
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- /* For Source detach during HardReset */
- if ((!vbus_valid) &&
- tcpc_dev->pd_wait_hard_reset_complete) {
- detach_by_cc = true;
- TYPEC_DBG("Detach_CC (HardReset)\r\n");
- }
-#endif
-
- if (detach_by_cc)
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
-
- return 0;
-}
-#endif /* TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS */
-
-static inline void typec_detach_wait_entry(struct tcpc_device *tcpc_dev)
-{
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- bool suspect_legacy = false;
-
- if (tcpc_dev->typec_state == typec_attachwait_src) {
- suspect_legacy = true;
- } else if (tcpc_dev->typec_state == typec_attached_src) {
- if (tcpc_dev->typec_attach_old != TYPEC_ATTACHED_SRC) {
- suspect_legacy = true;
- } else {
- tcpc_dev->typec_legacy_cable = false;
- tcpc_dev->typec_legacy_cable_suspect = 0;
- }
- }
-
- if (suspect_legacy) {
- tcpc_dev->typec_legacy_cable_suspect++;
- TYPEC_DBG("LC_suspect: %d\r\n",
- tcpc_dev->typec_legacy_cable_suspect);
- }
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
- switch (tcpc_dev->typec_state) {
-#ifdef TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS
- case typec_attached_snk:
- typec_attached_snk_cc_detach(tcpc_dev);
- break;
-#endif /* TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS */
-
- case typec_audioaccessory:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_CCDEBOUNCE);
- break;
-
-#ifdef TYPEC_EXIT_ATTACHED_SRC_NO_DEBOUNCE
- case typec_attached_src:
- TYPEC_INFO("Exit Attached.SRC immediately\r\n");
- tcpc_reset_typec_debounce_timer(tcpc_dev);
-
- /* force to terminate TX */
- tcpci_init(tcpc_dev, true);
-
- typec_cc_src_remove_entry(tcpc_dev);
- typec_alert_attach_state_change(tcpc_dev);
- break;
-#endif /* TYPEC_EXIT_ATTACHED_SRC_NO_DEBOUNCE */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- case typec_try_src:
- if (tcpc_dev->typec_drp_try_timeout) {
- tcpc_enable_timer(tcpc_dev,
- TYPEC_TIMER_PDDEBOUNCE);
- } else {
- tcpc_reset_typec_debounce_timer(tcpc_dev);
- TYPEC_DBG("[Try] Igrone cc_detach\r\n");
- }
- break;
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- case typec_trywait_src:
- if (tcpc_dev->typec_drp_try_timeout) {
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
- } else {
- tcpc_reset_typec_debounce_timer(tcpc_dev);
- TYPEC_DBG("[Try] Igrone cc_detach\r\n");
- }
- break;
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
- default:
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
- break;
- }
-}
-
-static inline bool typec_is_cc_attach(struct tcpc_device *tcpc_dev)
-{
- bool cc_attach = false;
- int cc1 = typec_get_cc1();
- int cc2 = typec_get_cc2();
- int cc_res = typec_get_cc_res();
-
- tcpc_dev->typec_cable_only = false;
-
- if (tcpc_dev->typec_attach_old) {
- if ((cc_res != TYPEC_CC_VOLT_OPEN) &&
- (cc_res != TYPEC_CC_VOLT_RA))
- cc_attach = true;
- } else {
- if (cc1 != TYPEC_CC_VOLT_OPEN)
- cc_attach = true;
-
- if (cc2 != TYPEC_CC_VOLT_OPEN)
- cc_attach = true;
-
- /* Cable Only, no device */
- if ((cc1 + cc2) == TYPEC_CC_VOLT_RA) {
- cc_attach = false;
- tcpc_dev->typec_cable_only = true;
- }
- }
-
- return cc_attach;
-}
-
-int tcpc_typec_handle_cc_change(struct tcpc_device *tcpc_dev)
-{
- int ret = tcpci_get_cc(tcpc_dev);
-
- if (ret < 0)
- return ret;
-
- if (typec_is_drp_toggling()) {
- TYPEC_DBG("[Waring] DRP Toggling\r\n");
- if (tcpc_dev->typec_lpm)
- tcpci_set_low_power_mode(tcpc_dev, true, TYPEC_CC_DRP);
- return 0;
- }
-
- TYPEC_INFO("[CC_Alert] %d/%d\r\n", typec_get_cc1(), typec_get_cc2());
-
- typec_disable_low_power_mode(tcpc_dev);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->pd_wait_pr_swap_complete) {
- TYPEC_DBG("[PR.Swap] Ignore CC_Alert\r\n");
- return 0;
- }
-
- if (tcpc_dev->pd_wait_error_recovery) {
- TYPEC_DBG("[Recovery] Ignore CC_Alert\r\n");
- return 0;
- }
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- if ((tcpc_dev->typec_state == typec_try_snk) &&
- (!tcpc_dev->typec_drp_try_timeout)) {
- TYPEC_DBG("[Try.SNK] Ignore CC_Alert\r\n");
- return 0;
- }
-
- if (tcpc_dev->typec_state == typec_trywait_src_pe) {
- TYPEC_DBG("[Try.PE] Ignore CC_Alert\r\n");
- return 0;
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- if (tcpc_dev->typec_state == typec_trywait_snk_pe) {
- TYPEC_DBG("[Try.PE] Ignore CC_Alert\r\n");
- return 0;
- }
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
- if (tcpc_dev->typec_state == typec_attachwait_snk ||
- tcpc_dev->typec_state == typec_attachwait_src)
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
- if (typec_is_cc_attach(tcpc_dev))
- typec_attach_wait_entry(tcpc_dev);
- else
- typec_detach_wait_entry(tcpc_dev);
-
- return 0;
-}
-
-/*
- * [BLOCK] Handle timeout event
- */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_STATE
-static inline int typec_handle_drp_try_timeout(struct tcpc_device *tcpc_dev)
-{
- bool not_detect, en_timer;
-
- tcpc_dev->typec_drp_try_timeout = true;
- tcpc_disable_timer(tcpc_dev, TYPEC_TRY_TIMER_DRP_TRY);
-
- if (typec_is_drp_toggling()) {
- TYPEC_DBG("[Waring] DRP Toggling\r\n");
- return 0;
- }
-
- not_detect = typec_is_cc_open();
-
- switch (tcpc_dev->typec_state) {
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- case typec_try_src:
- en_timer = not_detect;
- break;
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCE */
-
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- case typec_trywait_src:
- en_timer = not_detect;
- break;
-
- case typec_try_snk:
- en_timer = true;
- break;
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
-
- default:
- en_timer = false;
- break;
- }
-
- if (en_timer)
- tcpc_enable_timer(tcpc_dev, TYPEC_TIMER_PDDEBOUNCE);
-
- return 0;
-}
-#endif /* CONFIG_TYPEC_CAP_TRY_STATE */
-
-static inline int typec_handle_debounce_timeout(struct tcpc_device *tcpc_dev)
-{
- if (typec_is_drp_toggling()) {
- TYPEC_DBG("[Waring] DRP Toggling\r\n");
- return 0;
- }
-
- typec_handle_cc_changed_entry(tcpc_dev);
- return 0;
-}
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-
-static inline int typec_handle_error_recovery_timeout(
- struct tcpc_device *tcpc_dev)
-{
- /* TODO: Check it later */
- tcpc_dev->typec_attach_new = TYPEC_UNATTACHED;
-
- mutex_lock(&tcpc_dev->access_lock);
- tcpc_dev->pd_wait_error_recovery = false;
- mutex_unlock(&tcpc_dev->access_lock);
-
- typec_unattach_wait_pe_idle_entry(tcpc_dev);
- typec_alert_attach_state_change(tcpc_dev);
-
- return 0;
-}
-
-static inline int typec_handle_pe_idle(struct tcpc_device *tcpc_dev)
-{
- switch (tcpc_dev->typec_state) {
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- case typec_trywait_snk_pe:
- typec_trywait_snk_entry(tcpc_dev);
- break;
-#endif
-
- case typec_unattachwait_pe:
- typec_unattached_entry(tcpc_dev);
- break;
-
- default:
- TYPEC_DBG("dummy_pe_idle\r\n");
- break;
- }
-
- return 0;
-}
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-static inline int typec_handle_src_reach_vsafe0v(struct tcpc_device *tcpc_dev)
-{
- if (typec_is_drp_toggling()) {
- TYPEC_DBG("[Waring] DRP Toggling\r\n");
- return 0;
- }
-
- typec_cc_src_detect_vsafe0v_entry(tcpc_dev);
- return 0;
-}
-
-static inline int typec_handle_src_toggle_timeout(struct tcpc_device *tcpc_dev)
-{
- if (tcpc_dev->typec_state == typec_unattached_src) {
- TYPEC_NEW_STATE(typec_unattached_snk);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_DRP);
- typec_enable_low_power_mode(tcpc_dev, TYPEC_CC_DRP);
- }
-
- return 0;
-}
-
-int tcpc_typec_handle_timeout(struct tcpc_device *tcpc_dev, u32 timer_id)
-{
- int ret = 0;
-
-#ifdef CONFIG_TYPEC_CAP_TRY_STATE
- if (timer_id == TYPEC_TRY_TIMER_DRP_TRY)
- return typec_handle_drp_try_timeout(tcpc_dev);
-#endif /* CONFIG_TYPEC_CAP_TRY_STATE */
-
- if (timer_id >= TYPEC_TIMER_START_ID)
- tcpc_reset_typec_debounce_timer(tcpc_dev);
- else if (timer_id >= TYPEC_RT_TIMER_START_ID)
- tcpc_disable_timer(tcpc_dev, timer_id);
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->pd_wait_pr_swap_complete) {
- TYPEC_DBG("[PR.Swap] Igrone timer_evt\r\n");
- return 0;
- }
-
- if (tcpc_dev->pd_wait_error_recovery &&
- (timer_id != TYPEC_TIMER_ERROR_RECOVERY)) {
- TYPEC_DBG("[Recovery] Igrone timer_evt\r\n");
- return 0;
- }
-#endif
-
- switch (timer_id) {
- case TYPEC_TIMER_CCDEBOUNCE:
- case TYPEC_TIMER_PDDEBOUNCE:
- ret = typec_handle_debounce_timeout(tcpc_dev);
- break;
-
-#ifdef CONFIG_USB_POWER_DELIVERY
- case TYPEC_TIMER_ERROR_RECOVERY:
- ret = typec_handle_error_recovery_timeout(tcpc_dev);
- break;
-
- case TYPEC_RT_TIMER_PE_IDLE:
- ret = typec_handle_pe_idle(tcpc_dev);
- break;
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- case TYPEC_RT_TIMER_SAFE0V_DELAY:
- ret = typec_handle_src_reach_vsafe0v(tcpc_dev);
- break;
-
- case TYPEC_TIMER_WAKEUP:
- if (tcpc_dev->typec_lpm || tcpc_dev->typec_cable_only) {
- tcpc_dev->typec_lpm = true;
- ret =
- tcpci_set_low_power_mode(
- tcpc_dev, true,
- (tcpc_dev->typec_role ==
- TYPEC_ROLE_SRC) ?
- TYPEC_CC_RP :
- TYPEC_CC_DRP);
- }
- break;
-
-#ifdef CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT
- case TYPEC_RT_TIMER_SAFE0V_TOUT:
- ret = tcpc_typec_handle_vsafe0v(tcpc_dev);
- break;
-#endif /* CONFIG_TYPEC_ATTACHED_SRC_SAFE0V_TIMEOUT */
-
- case TYPEC_TIMER_DRP_SRC_TOGGLE:
- ret = typec_handle_src_toggle_timeout(tcpc_dev);
- break;
- }
-
- return ret;
-}
-
-/*
- * [BLOCK] Handle ps-change event
- */
-
-static inline int typec_handle_vbus_present(struct tcpc_device *tcpc_dev)
-{
- switch (tcpc_dev->typec_wait_ps_change) {
- case TYPEC_WAIT_PS_SNK_VSAFE5V:
- typec_cc_snk_detect_vsafe5v_entry(tcpc_dev);
- typec_alert_attach_state_change(tcpc_dev);
- break;
- case TYPEC_WAIT_PS_SRC_VSAFE5V:
- typec_source_attached_with_vbus_entry(tcpc_dev);
- typec_alert_attach_state_change(tcpc_dev);
- break;
- }
-
- return 0;
-}
-
-static inline int typec_attached_snk_vbus_absent(struct tcpc_device *tcpc_dev)
-{
-#ifdef TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->pd_wait_hard_reset_complete ||
- tcpc_dev->pd_hard_reset_event_pending) {
- if (typec_get_cc_res() != TYPEC_CC_VOLT_OPEN) {
- TYPEC_DBG
- ("Ignore vbus_absent(snk), HReset & CC!=0\r\n");
- return 0;
- }
- }
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
- typec_unattach_wait_pe_idle_entry(tcpc_dev);
- typec_alert_attach_state_change(tcpc_dev);
-#endif /* TYPEC_EXIT_ATTACHED_SNK_VIA_VBUS */
-
- return 0;
-}
-
-static inline int typec_handle_vbus_absent(struct tcpc_device *tcpc_dev)
-{
-#ifdef CONFIG_USB_POWER_DELIVERY
- if (tcpc_dev->pd_wait_pr_swap_complete) {
- TYPEC_DBG("[PR.Swap] Igrone vbus_absent\r\n");
- return 0;
- }
-
- if (tcpc_dev->pd_wait_error_recovery) {
- TYPEC_DBG("[Recovery] Igrone vbus_absent\r\n");
- return 0;
- }
-#endif
-
- if (tcpc_dev->typec_state == typec_attached_snk)
- typec_attached_snk_vbus_absent(tcpc_dev);
-
-#ifndef CONFIG_TCPC_VSAFE0V_DETECT
- tcpc_typec_handle_vsafe0v(tcpc_dev);
-#endif /* #ifdef CONFIG_TCPC_VSAFE0V_DETECT */
-
- return 0;
-}
-
-int tcpc_typec_handle_ps_change(struct tcpc_device *tcpc_dev, int vbus_level)
-{
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- if (tcpc_dev->typec_legacy_cable) {
- if (vbus_level) {
- TYPEC_INFO("LC->Attached\r\n");
- tcpc_dev->typec_legacy_cable = false;
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
- } else {
- TYPEC_INFO("LC->Detached\r\n");
- tcpc_dev->typec_legacy_cable = false;
- tcpci_set_cc(tcpc_dev, TYPEC_CC_DRP);
- typec_enable_low_power_mode(tcpc_dev, TYPEC_CC_DRP);
- }
- return 0;
- }
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
- if (typec_is_drp_toggling()) {
- TYPEC_DBG("[Waring] DRP Toggling\r\n");
- return 0;
- }
-
- if (vbus_level)
- return typec_handle_vbus_present(tcpc_dev);
- else
- return typec_handle_vbus_absent(tcpc_dev);
-}
-
-/*
- * [BLOCK] Handle PE event
- */
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-
-int tcpc_typec_advertise_explicit_contract(struct tcpc_device *tcpc_dev)
-{
- if (tcpc_dev->typec_local_rp_level == TYPEC_CC_RP_DFT)
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RP_1_5);
-
- return 0;
-}
-
-int tcpc_typec_handle_pe_pr_swap(struct tcpc_device *tcpc_dev)
-{
- int ret = 0;
-
- mutex_lock(&tcpc_dev->typec_lock);
- switch (tcpc_dev->typec_state) {
- case typec_attached_snk:
- TYPEC_NEW_STATE(typec_attached_src);
- tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SRC;
- tcpci_set_cc(tcpc_dev, tcpc_dev->typec_local_rp_level);
- break;
- case typec_attached_src:
- TYPEC_NEW_STATE(typec_attached_snk);
- tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SNK;
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
- break;
- default:
- break;
- }
- mutex_unlock(&tcpc_dev->typec_lock);
- return ret;
-}
-
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-/*
- * [BLOCK] Handle reach vSafe0V event
- */
-
-int tcpc_typec_handle_vsafe0v(struct tcpc_device *tcpc_dev)
-{
- if (tcpc_dev->typec_wait_ps_change == TYPEC_WAIT_PS_SRC_VSAFE0V)
- typec_handle_src_reach_vsafe0v(tcpc_dev);
-
- return 0;
-}
-
-/*
- * [BLOCK] TCPCI TypeC I/F
- */
-
-static const char *const typec_role_name[] = {
- "UNKNOWN",
- "SNK",
- "SRC",
- "DRP",
- "TrySRC",
- "TrySNK",
-};
-
-#ifndef CONFIG_USB_POWER_DELIVERY
-int tcpc_typec_swap_role(struct tcpc_device *tcpc_dev)
-{
- if (tcpc_dev->typec_role < TYPEC_ROLE_DRP)
- return -1;
- TYPEC_INFO("%s\r\n", __func__);
-
- switch (tcpc_dev->typec_state) {
- case typec_attached_src:
-#ifdef CONFIG_TYPEC_CAP_TRY_SOURCE
- typec_trywait_snk_pe_entry(tcpc_dev);
-#else
- TYPEC_INFO("SRC->SNK (X)\r\n");
-#endif /* CONFIG_TYPEC_CAP_TRY_SOURCR */
- break;
- case typec_attached_snk:
-#ifdef CONFIG_TYPEC_CAP_TRY_SINK
- typec_trywait_src_pe_entry(tcpc_dev);
-#else
- TYPEC_INFO("SNK->SRC (X)\r\n");
-#endif /* CONFIG_TYPEC_CAP_TRY_SINK */
- break;
- }
- return typec_alert_attach_state_change(tcpc_dev);
-}
-#endif /* ifndef CONFIG_USB_POWER_DELIVERY */
-
-int tcpc_typec_set_rp_level(struct tcpc_device *tcpc_dev, u8 res)
-{
- switch (res) {
- case TYPEC_CC_RP_DFT:
- case TYPEC_CC_RP_1_5:
- case TYPEC_CC_RP_3_0:
- TYPEC_INFO("TypeC-Rp: %d\r\n", res);
- tcpc_dev->typec_local_rp_level = res;
- break;
-
- default:
- TYPEC_INFO("TypeC-Unknown-Rp (%d)\r\n", res);
- return -1;
- }
-
-#ifdef CONFIG_USB_PD_DBG_ALWAYS_LOCAL_RP
- tcpci_set_cc(tcpc_dev, tcpc_dev->typec_local_rp_level);
-#else
- if ((tcpc_dev->typec_attach_old != TYPEC_UNATTACHED) &&
- (tcpc_dev->typec_attach_new != TYPEC_UNATTACHED)) {
- return tcpci_set_cc(tcpc_dev, res);
- }
-#endif
-
- return 0;
-}
-
-int tcpc_typec_change_role(
- struct tcpc_device *tcpc_dev, u8 typec_role)
-{
- u8 local_cc;
- bool force_unattach = false;
-
- if (typec_role == TYPEC_ROLE_UNKNOWN ||
- typec_role >= TYPEC_ROLE_NR) {
- TYPEC_INFO("Wrong TypeC-Role: %d\r\n", typec_role);
- return -1;
- }
-
- mutex_lock(&tcpc_dev->access_lock);
-
- tcpc_dev->typec_role = typec_role;
- TYPEC_INFO("typec_new_role: %s\r\n", typec_role_name[typec_role]);
-
- local_cc = tcpc_dev->typec_local_cc & 0x07;
-
- if (typec_role == TYPEC_ROLE_SNK && local_cc == TYPEC_CC_RP)
- force_unattach = true;
-
- if (typec_role == TYPEC_ROLE_SRC && local_cc == TYPEC_CC_RD)
- force_unattach = true;
-
- if (tcpc_dev->typec_attach_new == TYPEC_UNATTACHED)
- force_unattach = true;
-
- if (force_unattach) {
- TYPEC_DBG("force_unattach\r\n");
- typec_disable_low_power_mode(tcpc_dev);
- typec_unattached_entry(tcpc_dev);
- }
-
- mutex_unlock(&tcpc_dev->access_lock);
- return 0;
-}
-
-#ifdef CONFIG_TYPEC_CAP_POWER_OFF_CHARGE
-static int typec_init_power_off_charge(struct tcpc_device *tcpc_dev)
-{
- int ret = tcpci_get_cc(tcpc_dev);
-
- if (ret < 0)
- return ret;
-
- if (tcpc_dev->typec_role == TYPEC_ROLE_SRC)
- return 0;
-
- if (typec_is_cc_open())
- return 0;
-
- if (!tcpci_check_vbus_valid(tcpc_dev))
- return 0;
-
- TYPEC_DBG("PowerOffCharge\r\n");
- TYPEC_DBG("init otg host no mache insert.\r\n");
-
- gpio_hub_power_on();
- gpio_hub_typec_power_off();
- hisi_usb_otg_event(CHARGER_DISCONNECT_EVENT);
- gpio_hub_switch_to_hub();
- hisi_usb_otg_event(ID_FALL_EVENT);
- oldstatus = TYPEC_HOST;
-
- TYPEC_NEW_STATE(typec_unattached_snk);
- typec_wait_ps_change(tcpc_dev, TYPEC_WAIT_PS_DISABLE);
-
- tcpci_set_cc(tcpc_dev, TYPEC_CC_OPEN);
- tcpci_set_cc(tcpc_dev, TYPEC_CC_RD);
-
- return 1;
-}
-#endif /* CONFIG_TYPEC_CAP_POWER_OFF_CHARGE */
-
-int tcpc_typec_init(struct tcpc_device *tcpc_dev, u8 typec_role)
-{
- int ret;
-
- if (typec_role >= TYPEC_ROLE_NR) {
- TYPEC_INFO("Wrong TypeC-Role: %d\r\n", typec_role);
- return -2;
- }
-
- TYPEC_INFO("typec_init: %s\r\n", typec_role_name[typec_role]);
-
- tcpc_dev->typec_role = typec_role;
- tcpc_dev->typec_attach_new = TYPEC_UNATTACHED;
- tcpc_dev->typec_attach_old = TYPEC_UNATTACHED;
-
- tcpc_dev->typec_remote_cc[0] = TYPEC_CC_VOLT_OPEN;
- tcpc_dev->typec_remote_cc[1] = TYPEC_CC_VOLT_OPEN;
-
-#ifdef CONFIG_TYPEC_CHECK_LEGACY_CABLE
- tcpc_dev->typec_legacy_cable = false;
- tcpc_dev->typec_legacy_cable_suspect = 0;
-#endif /* CONFIG_TYPEC_CHECK_LEGACY_CABLE */
-
-#ifdef CONFIG_TYPEC_CAP_POWER_OFF_CHARGE
- ret = typec_init_power_off_charge(tcpc_dev);
- if (ret != 0)
- return ret;
-#endif /* CONFIG_TYPEC_CAP_POWER_OFF_CHARGE */
-
- if (typec_role >= TYPEC_ROLE_DRP) {
- tcpci_get_cc(tcpc_dev);
- if (tcpc_dev->typec_remote_cc[0] == TYPEC_CC_VOLT_OPEN &&
- tcpc_dev->typec_remote_cc[1] == TYPEC_CC_VOLT_OPEN) {
- tcpci_set_cc(tcpc_dev, TYPEC_CC_OPEN);
- mdelay(50);
- }
- }
-
-#ifdef CONFIG_TYPEC_POWER_CTRL_INIT
- tcpc_dev->typec_power_ctrl = true;
-#endif /* CONFIG_TYPEC_POWER_CTRL_INIT */
-
- typec_unattached_entry(tcpc_dev);
- return 0;
-}
-
-void tcpc_typec_deinit(struct tcpc_device *tcpc_dev)
-{
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Richtek Technology Corp.
- *
- * Power Delivery Managert Driver
- *
- * Author: TH <tsunghan_tsai@richtek.com>
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/hisi/usb/pd/richtek/tcpm.h>
-#include <linux/hisi/usb/pd/richtek/pd_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci.h>
-#include <linux/hisi/usb/pd/richtek/pd_policy_engine.h>
-#include <linux/hisi/usb/pd/richtek/pd_dpm_core.h>
-#include <linux/hisi/usb/pd/richtek/tcpci_typec.h>
-
-/* Inquire TCPC status */
-
-int tcpm_inquire_remote_cc(struct tcpc_device *tcpc_dev,
- u8 *cc1, u8 *cc2, bool from_ic)
-{
- int rv = 0;
-
- if (from_ic) {
- rv = tcpci_get_cc(tcpc_dev);
- if (rv < 0)
- return rv;
- }
-
- *cc1 = tcpc_dev->typec_remote_cc[0];
- *cc2 = tcpc_dev->typec_remote_cc[1];
- return 0;
-}
-
-int tcpm_inquire_vbus_level(
- struct tcpc_device *tcpc_dev, bool from_ic)
-{
- int rv = 0;
- u16 power_status = 0;
-
- if (from_ic) {
- rv = tcpci_get_power_status(tcpc_dev, &power_status);
- if (rv < 0)
- return rv;
-
- tcpci_vbus_level_init(tcpc_dev, power_status);
- }
-
- return tcpc_dev->vbus_level;
-}
-
-bool tcpm_inquire_cc_polarity(
- struct tcpc_device *tcpc_dev)
-{
- return tcpc_dev->typec_polarity;
-}
-
-u8 tcpm_inquire_typec_attach_state(
- struct tcpc_device *tcpc_dev)
-{
- return tcpc_dev->typec_attach_new;
-}
-
-u8 tcpm_inquire_typec_role(
- struct tcpc_device *tcpc_dev)
-{
- return tcpc_dev->typec_role;
-}
-
-u8 tcpm_inquire_typec_local_rp(
- struct tcpc_device *tcpc_dev)
-{
- u8 level;
-
- switch (tcpc_dev->typec_local_rp_level) {
- case TYPEC_CC_RP_1_5:
- level = 1;
- break;
-
- case TYPEC_CC_RP_3_0:
- level = 2;
- break;
-
- default:
- case TYPEC_CC_RP_DFT:
- level = 0;
- break;
- }
-
- return level;
-}
-
-int tcpm_typec_set_rp_level(
- struct tcpc_device *tcpc_dev, u8 level)
-{
- u8 res;
-
- if (level == 2)
- res = TYPEC_CC_RP_3_0;
- else if (level == 1)
- res = TYPEC_CC_RP_1_5;
- else
- res = TYPEC_CC_RP_DFT;
-
- return tcpc_typec_set_rp_level(tcpc_dev, res);
-}
-
-int tcpm_typec_change_role(
- struct tcpc_device *tcpc_dev, u8 typec_role)
-{
- return tcpc_typec_change_role(tcpc_dev, typec_role);
-}
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-
-bool tcpm_inquire_pd_connected(
- struct tcpc_device *tcpc_dev)
-{
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- return pd_port->pd_connected;
-}
-
-bool tcpm_inquire_pd_prev_connected(
- struct tcpc_device *tcpc_dev)
-{
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- return pd_port->pd_prev_connected;
-}
-
-u8 tcpm_inquire_pd_data_role(
- struct tcpc_device *tcpc_dev)
-{
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- return pd_port->data_role;
-}
-
-u8 tcpm_inquire_pd_power_role(
- struct tcpc_device *tcpc_dev)
-{
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- return pd_port->power_role;
-}
-
-u8 tcpm_inquire_pd_vconn_role(
- struct tcpc_device *tcpc_dev)
-{
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- return pd_port->vconn_source;
-}
-
-#endif /* CONFIG_USB_POWER_DELIVERY */
-
-/* Request TCPC to send PD Request */
-
-#ifdef CONFIG_USB_POWER_DELIVERY
-
-int tcpm_power_role_swap(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_PR_SWAP);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_power_role_swap);
-
-int tcpm_data_role_swap(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_DR_SWAP);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_data_role_swap);
-
-int tcpm_vconn_swap(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_VCONN_SWAP);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_vconn_swap);
-
-int tcpm_goto_min(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_GOTOMIN);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_goto_min);
-
-int tcpm_soft_reset(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_SOFTRESET);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_soft_reset);
-
-int tcpm_hard_reset(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_HARDRESET);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_hard_reset);
-
-int tcpm_get_source_cap(
- struct tcpc_device *tcpc_dev, struct tcpm_power_cap *cap)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_GET_SOURCE_CAP);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- /* TODO: Finish it later */
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_get_source_cap);
-
-int tcpm_get_sink_cap(
- struct tcpc_device *tcpc_dev, struct tcpm_power_cap *cap)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_GET_SINK_CAP);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- /* TODO: Finish it later */
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_get_sink_cap);
-
-int tcpm_bist_cm2(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_pd_request_event(pd_port,
- PD_DPM_PD_REQUEST_BIST_CM2);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- /* TODO: Finish it later */
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_bist_cm2);
-
-int tcpm_request(struct tcpc_device *tcpc_dev, int mv, int ma)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- mutex_lock(&pd_port->pd_lock);
- ret = pd_dpm_send_request(pd_port, mv, ma);
- mutex_unlock(&pd_port->pd_lock);
-
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_request);
-
-int tcpm_error_recovery(struct tcpc_device *tcpc_dev)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- ret = pd_put_dpm_event(pd_port, PD_DPM_ERROR_RECOVERY);
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-
-int tcpm_discover_cable(struct tcpc_device *tcpc_dev, u32 *vdos)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- mutex_lock(&pd_port->pd_lock);
- pd_port->dpm_flags |= DPM_FLAGS_CHECK_CABLE_ID;
- ret = vdm_put_dpm_discover_cable_event(pd_port);
- mutex_unlock(&pd_port->pd_lock);
-
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-
-int tcpm_vdm_request_id(struct tcpc_device *tcpc_dev,
- u8 *cnt, u8 *payload)
-{
- bool ret;
- pd_port_t *pd_port = &tcpc_dev->pd_port;
-
- mutex_lock(&pd_port->pd_lock);
- ret = vdm_put_dpm_vdm_request_event(
- pd_port, PD_DPM_VDM_REQUEST_DISCOVER_ID);
- mutex_unlock(&pd_port->pd_lock);
-
- if (!ret)
- return TCPM_ERROR_PUT_EVENT;
-
- return TCPM_SUCCESS;
-}
-
-int tcpm_notify_vbus_stable(
- struct tcpc_device *tcpc_dev)
-{
-#if CONFIG_USB_PD_VBUS_STABLE_TOUT
- tcpc_disable_timer(tcpc_dev, PD_TIMER_VBUS_STABLE);
-#endif
-
- pd_put_vbus_stable_event(tcpc_dev);
- return TCPM_SUCCESS;
-}
-EXPORT_SYMBOL(tcpm_notify_vbus_stable);
-
-#endif /* CONFIG_USB_POWER_DELIVERY */