LF-10575-3 usb: chipidea: imx: add HSIO blkctl wakup handling

There are two sets (HSIO blkctl and USB non-core) of wakeup setting when
HSIO blkctl exists. To support wakup when HSIO domain power is lost, HSIO
blkctl wakup handling is a must. This will add the wakup handling for HSIO
blkctl cases.

Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
Reviewed-by: Jun Li <jun.li@nxp.com>
This commit is contained in:
Xu Yang 2023-11-15 18:16:54 +08:00
parent 2be33a6a8e
commit 98af898785

View File

@ -139,6 +139,21 @@
#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
MX6_BM_ID_WAKEUP | MX6SX_BM_DPDM_WAKEUP_EN)
/*
* HSIO Block Control Register
*/
#define BLKCTL_USB_WAKEUP_CTRL 0x0
#define BLKCTL_OTG_WAKE_ENABLE BIT(31)
#define BLKCTL_OTG_ID_WAKEUP_EN BIT(2)
#define BLKCTL_OTG_VBUS_WAKEUP_EN BIT(1)
#define BLKCTL_OTG_DPDM_WAKEUP_EN BIT(0)
#define BLKCTL_WAKEUP_SOURCE (BLKCTL_OTG_WAKE_ENABLE | \
BLKCTL_OTG_ID_WAKEUP_EN | \
BLKCTL_OTG_VBUS_WAKEUP_EN | \
BLKCTL_OTG_DPDM_WAKEUP_EN)
struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct imx_usbmisc_data *data);
@ -159,6 +174,7 @@ struct usbmisc_ops {
struct imx_usbmisc {
void __iomem *base;
void __iomem *blkctl;
spinlock_t lock;
const struct usbmisc_ops *ops;
};
@ -1016,6 +1032,76 @@ static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data)
return 0;
}
static u32 usbmisc_blkctl_wakeup_setting(struct imx_usbmisc_data *data)
{
u32 wakeup_setting = BLKCTL_WAKEUP_SOURCE;
if (data->ext_id || data->available_role != USB_DR_MODE_OTG)
wakeup_setting &= ~BLKCTL_OTG_ID_WAKEUP_EN;
if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST)
wakeup_setting &= ~BLKCTL_OTG_VBUS_WAKEUP_EN;
return wakeup_setting;
}
static int usbmisc_imx95_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL);
val &= ~BLKCTL_WAKEUP_SOURCE;
if (enabled)
val |= usbmisc_blkctl_wakeup_setting(data);
writel(val, usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL);
spin_unlock_irqrestore(&usbmisc->lock, flags);
return 0;
}
static int usbmisc_imx95_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 reg;
if (data->index >= 1)
return -EINVAL;
spin_lock_irqsave(&usbmisc->lock, flags);
reg = readl(usbmisc->base);
if (data->disable_oc) {
reg |= MX6_BM_OVER_CUR_DIS;
} else {
reg &= ~MX6_BM_OVER_CUR_DIS;
/*
* If the polarity is not configured keep it as setup by the
* bootloader.
*/
if (data->oc_pol_configured && data->oc_pol_active_low)
reg |= MX6_BM_OVER_CUR_POLARITY;
else if (data->oc_pol_configured)
reg &= ~MX6_BM_OVER_CUR_POLARITY;
}
/* If the polarity is not set keep it as setup by the bootlader */
if (data->pwr_pol == 1)
reg |= MX6_BM_PWR_POLARITY;
writel(reg, usbmisc->base);
spin_unlock_irqrestore(&usbmisc->lock, flags);
/* Will use HSIO blkctl wakeup as source, so disable usbmisc wakeup */
usbmisc_imx7d_set_wakeup(data, false);
return 0;
}
static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
@ -1068,6 +1154,14 @@ static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
.power_lost_check = usbmisc_imx7d_power_lost_check,
};
static const struct usbmisc_ops imx95_usbmisc_ops = {
.init = usbmisc_imx95_init,
.set_wakeup = usbmisc_imx95_set_wakeup,
.charger_detection = imx7d_charger_detection,
.power_lost_check = usbmisc_imx7d_power_lost_check,
.vbus_comparator_on = usbmisc_imx7d_vbus_comparator_on,
};
static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
@ -1285,6 +1379,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx7ulp-usbmisc",
.data = &imx7ulp_usbmisc_ops,
},
{
.compatible = "fsl,imx95-usbmisc",
.data = &imx95_usbmisc_ops,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
@ -1303,6 +1401,12 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx95-usbmisc")) {
data->blkctl = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(data->blkctl))
return PTR_ERR(data->blkctl);
}
data->ops = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, data);