USB Chipidea updates for v4.4-rc1
- Use extcon framework for VBUS and ID detect - Add imx6sx and imx7d support - Other small changes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWKEKdAAoJEEhZKYFQ1nG7dysH/jmFSatDJvgA7woliRZ7p0H/ elNu6AOjqBnsi23Vp54IOVWYTVIDhLsXxlzEOgO6XXfsI99TqFQIIS2VYSo6xues Eq5hIxh5n9uue3VMnw9bxYHcFkFG9LDAlyMXecEayAB74UqnQLbo2bRDfnSopaf1 dEOq9mdT8llYbtVww6bVXtL78wgwxVk1gTfISllxgt7DEuYwgT+gQJCDLrmkGPn0 XfiaZWamNmDlQd4z/qqoG65+yNmZZMZQKtugCx4MoiBbHVclRN7j2eNsCZ0y6dsZ qxs+CazL/IeYCqxRRXl5Fopraer1uJeOPeFgA+lRV6WPhMEe7eg6ojkDp/8Y18Y= =Dh+g -----END PGP SIGNATURE----- Merge tag 'usb-ci-v4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-next Peter writes: USB Chipidea updates for v4.4-rc1 - Use extcon framework for VBUS and ID detect - Add imx6sx and imx7d support - Other small changes
This commit is contained in:
commit
9e43643b11
@ -27,10 +27,6 @@ Optional properties:
|
|||||||
- vbus-supply: reference to the VBUS regulator
|
- vbus-supply: reference to the VBUS regulator
|
||||||
- maximum-speed: limit the maximum connection speed to "full-speed".
|
- maximum-speed: limit the maximum connection speed to "full-speed".
|
||||||
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
|
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
|
||||||
- fsl,usbmisc: (FSL only) phandler of non-core register device, with one
|
|
||||||
argument that indicate usb controller index
|
|
||||||
- disable-over-current: (FSL only) disable over current detect
|
|
||||||
- external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus
|
|
||||||
- itc-setting: interrupt threshold control register control, the setting
|
- itc-setting: interrupt threshold control register control, the setting
|
||||||
should be aligned with ITC bits at register USBCMD.
|
should be aligned with ITC bits at register USBCMD.
|
||||||
- ahb-burst-config: it is vendor dependent, the required value should be
|
- ahb-burst-config: it is vendor dependent, the required value should be
|
||||||
@ -41,11 +37,28 @@ Optional properties:
|
|||||||
- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
|
- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
|
||||||
(4 bytes), This register represents the maximum length of a the burst
|
(4 bytes), This register represents the maximum length of a the burst
|
||||||
in 32-bit words while moving data from system memory to the USB
|
in 32-bit words while moving data from system memory to the USB
|
||||||
bus, changing this value takes effect only the SBUSCFG.AHBBRST is 0.
|
bus, the value of this property will only take effect if property
|
||||||
|
"ahb-burst-config" is set to 0, if this property is missing the reset
|
||||||
|
default of the hardware implementation will be used.
|
||||||
- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
|
- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
|
||||||
(4 bytes), This register represents the maximum length of a the burst
|
(4 bytes), This register represents the maximum length of a the burst
|
||||||
in 32-bit words while moving data from the USB bus to system memory,
|
in 32-bit words while moving data from the USB bus to system memory,
|
||||||
changing this value takes effect only the SBUSCFG.AHBBRST is 0.
|
the value of this property will only take effect if property
|
||||||
|
"ahb-burst-config" is set to 0, if this property is missing the reset
|
||||||
|
default of the hardware implementation will be used.
|
||||||
|
- extcon: phandles to external connector devices. First phandle should point to
|
||||||
|
external connector, which provide "USB" cable events, the second should point
|
||||||
|
to external connector device, which provide "USB-HOST" cable events. If one
|
||||||
|
of the external connector devices is not required, empty <0> phandle should
|
||||||
|
be specified.
|
||||||
|
- phy-clkgate-delay-us: the delay time (us) between putting the PHY into
|
||||||
|
low power mode and gating the PHY clock.
|
||||||
|
|
||||||
|
i.mx specific properties
|
||||||
|
- fsl,usbmisc: phandler of non-core register device, with one
|
||||||
|
argument that indicate usb controller index
|
||||||
|
- disable-over-current: disable over current detect
|
||||||
|
- external-vbus-divider: enables off-chip resistor divider for Vbus
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -62,4 +75,6 @@ Example:
|
|||||||
ahb-burst-config = <0x0>;
|
ahb-burst-config = <0x0>;
|
||||||
tx-burst-size-dword = <0x10>; /* 64 bytes */
|
tx-burst-size-dword = <0x10>; /* 64 bytes */
|
||||||
rx-burst-size-dword = <0x10>;
|
rx-burst-size-dword = <0x10>;
|
||||||
|
extcon = <0>, <&usb_id>;
|
||||||
|
phy-clkgate-delay-us = <400>;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
config USB_CHIPIDEA
|
config USB_CHIPIDEA
|
||||||
tristate "ChipIdea Highspeed Dual Role Controller"
|
tristate "ChipIdea Highspeed Dual Role Controller"
|
||||||
depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
|
depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
|
||||||
|
select EXTCON
|
||||||
help
|
help
|
||||||
Say Y here if your system has a dual role high speed USB
|
Say Y here if your system has a dual role high speed USB
|
||||||
controller based on ChipIdea silicon IP. Currently, only the
|
controller based on ChipIdea silicon IP. Currently, only the
|
||||||
|
@ -56,12 +56,23 @@ static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
|
|||||||
CI_HDRC_DISABLE_HOST_STREAMING,
|
CI_HDRC_DISABLE_HOST_STREAMING,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
|
||||||
|
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||||
|
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
|
||||||
|
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
||||||
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
|
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
|
||||||
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
|
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
|
||||||
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
|
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
|
||||||
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
|
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
|
||||||
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
|
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
|
||||||
|
{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
|
||||||
|
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
|
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
|
||||||
|
@ -142,16 +142,16 @@ static const struct pci_device_id ci_hdrc_pci_id_table[] = {
|
|||||||
.driver_data = (kernel_ulong_t)&pci_platdata,
|
.driver_data = (kernel_ulong_t)&pci_platdata,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
|
PCI_VDEVICE(INTEL, 0x0811),
|
||||||
.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
|
.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
|
PCI_VDEVICE(INTEL, 0x0829),
|
||||||
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* Intel Clovertrail */
|
/* Intel Clovertrail */
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006),
|
PCI_VDEVICE(INTEL, 0xe006),
|
||||||
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
||||||
},
|
},
|
||||||
{ 0 } /* end: all zeroes */
|
{ 0 } /* end: all zeroes */
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/extcon.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@ -602,9 +603,45 @@ static irqreturn_t ci_irq(int irq, void *data)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
|
||||||
|
void *ptr)
|
||||||
|
{
|
||||||
|
struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb);
|
||||||
|
struct ci_hdrc *ci = vbus->ci;
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
vbus->state = true;
|
||||||
|
else
|
||||||
|
vbus->state = false;
|
||||||
|
|
||||||
|
vbus->changed = true;
|
||||||
|
|
||||||
|
ci_irq(ci->irq, ci);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ci_id_notifier(struct notifier_block *nb, unsigned long event,
|
||||||
|
void *ptr)
|
||||||
|
{
|
||||||
|
struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb);
|
||||||
|
struct ci_hdrc *ci = id->ci;
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
id->state = false;
|
||||||
|
else
|
||||||
|
id->state = true;
|
||||||
|
|
||||||
|
id->changed = true;
|
||||||
|
|
||||||
|
ci_irq(ci->irq, ci);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
static int ci_get_platdata(struct device *dev,
|
static int ci_get_platdata(struct device *dev,
|
||||||
struct ci_hdrc_platform_data *platdata)
|
struct ci_hdrc_platform_data *platdata)
|
||||||
{
|
{
|
||||||
|
struct extcon_dev *ext_vbus, *ext_id;
|
||||||
|
struct ci_hdrc_cable *cable;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!platdata->phy_mode)
|
if (!platdata->phy_mode)
|
||||||
@ -651,6 +688,10 @@ static int ci_get_platdata(struct device *dev,
|
|||||||
if (usb_get_maximum_speed(dev) == USB_SPEED_FULL)
|
if (usb_get_maximum_speed(dev) == USB_SPEED_FULL)
|
||||||
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
|
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
|
||||||
|
|
||||||
|
if (of_find_property(dev->of_node, "phy-clkgate-delay-us", NULL))
|
||||||
|
of_property_read_u32(dev->of_node, "phy-clkgate-delay-us",
|
||||||
|
&platdata->phy_clkgate_delay_us);
|
||||||
|
|
||||||
platdata->itc_setting = 1;
|
platdata->itc_setting = 1;
|
||||||
if (of_find_property(dev->of_node, "itc-setting", NULL)) {
|
if (of_find_property(dev->of_node, "itc-setting", NULL)) {
|
||||||
ret = of_property_read_u32(dev->of_node, "itc-setting",
|
ret = of_property_read_u32(dev->of_node, "itc-setting",
|
||||||
@ -695,9 +736,91 @@ static int ci_get_platdata(struct device *dev,
|
|||||||
platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
|
platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ext_id = ERR_PTR(-ENODEV);
|
||||||
|
ext_vbus = ERR_PTR(-ENODEV);
|
||||||
|
if (of_property_read_bool(dev->of_node, "extcon")) {
|
||||||
|
/* Each one of them is not mandatory */
|
||||||
|
ext_vbus = extcon_get_edev_by_phandle(dev, 0);
|
||||||
|
if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV)
|
||||||
|
return PTR_ERR(ext_vbus);
|
||||||
|
|
||||||
|
ext_id = extcon_get_edev_by_phandle(dev, 1);
|
||||||
|
if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV)
|
||||||
|
return PTR_ERR(ext_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
cable = &platdata->vbus_extcon;
|
||||||
|
cable->nb.notifier_call = ci_vbus_notifier;
|
||||||
|
cable->edev = ext_vbus;
|
||||||
|
|
||||||
|
if (!IS_ERR(ext_vbus)) {
|
||||||
|
ret = extcon_get_cable_state_(cable->edev, EXTCON_USB);
|
||||||
|
if (ret)
|
||||||
|
cable->state = true;
|
||||||
|
else
|
||||||
|
cable->state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cable = &platdata->id_extcon;
|
||||||
|
cable->nb.notifier_call = ci_id_notifier;
|
||||||
|
cable->edev = ext_id;
|
||||||
|
|
||||||
|
if (!IS_ERR(ext_id)) {
|
||||||
|
ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST);
|
||||||
|
if (ret)
|
||||||
|
cable->state = false;
|
||||||
|
else
|
||||||
|
cable->state = true;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ci_extcon_register(struct ci_hdrc *ci)
|
||||||
|
{
|
||||||
|
struct ci_hdrc_cable *id, *vbus;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
id = &ci->platdata->id_extcon;
|
||||||
|
id->ci = ci;
|
||||||
|
if (!IS_ERR(id->edev)) {
|
||||||
|
ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST,
|
||||||
|
&id->nb);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(ci->dev, "register ID failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vbus = &ci->platdata->vbus_extcon;
|
||||||
|
vbus->ci = ci;
|
||||||
|
if (!IS_ERR(vbus->edev)) {
|
||||||
|
ret = extcon_register_notifier(vbus->edev, EXTCON_USB,
|
||||||
|
&vbus->nb);
|
||||||
|
if (ret < 0) {
|
||||||
|
extcon_unregister_notifier(id->edev, EXTCON_USB_HOST,
|
||||||
|
&id->nb);
|
||||||
|
dev_err(ci->dev, "register VBUS failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ci_extcon_unregister(struct ci_hdrc *ci)
|
||||||
|
{
|
||||||
|
struct ci_hdrc_cable *cable;
|
||||||
|
|
||||||
|
cable = &ci->platdata->id_extcon;
|
||||||
|
if (!IS_ERR(cable->edev))
|
||||||
|
extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST,
|
||||||
|
&cable->nb);
|
||||||
|
|
||||||
|
cable = &ci->platdata->vbus_extcon;
|
||||||
|
if (!IS_ERR(cable->edev))
|
||||||
|
extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb);
|
||||||
|
}
|
||||||
|
|
||||||
static DEFINE_IDA(ci_ida);
|
static DEFINE_IDA(ci_ida);
|
||||||
|
|
||||||
struct platform_device *ci_hdrc_add_device(struct device *dev,
|
struct platform_device *ci_hdrc_add_device(struct device *dev,
|
||||||
@ -921,6 +1044,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto stop;
|
goto stop;
|
||||||
|
|
||||||
|
ret = ci_extcon_register(ci);
|
||||||
|
if (ret)
|
||||||
|
goto stop;
|
||||||
|
|
||||||
if (ci->supports_runtime_pm) {
|
if (ci->supports_runtime_pm) {
|
||||||
pm_runtime_set_active(&pdev->dev);
|
pm_runtime_set_active(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
@ -938,6 +1065,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
ci_extcon_unregister(ci);
|
||||||
stop:
|
stop:
|
||||||
ci_role_destroy(ci);
|
ci_role_destroy(ci);
|
||||||
deinit_phy:
|
deinit_phy:
|
||||||
@ -957,6 +1085,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbg_remove_files(ci);
|
dbg_remove_files(ci);
|
||||||
|
ci_extcon_unregister(ci);
|
||||||
ci_role_destroy(ci);
|
ci_role_destroy(ci);
|
||||||
ci_hdrc_enter_lpm(ci, true);
|
ci_hdrc_enter_lpm(ci, true);
|
||||||
ci_usb_phy_exit(ci);
|
ci_usb_phy_exit(ci);
|
||||||
@ -996,6 +1125,9 @@ static void ci_controller_suspend(struct ci_hdrc *ci)
|
|||||||
{
|
{
|
||||||
disable_irq(ci->irq);
|
disable_irq(ci->irq);
|
||||||
ci_hdrc_enter_lpm(ci, true);
|
ci_hdrc_enter_lpm(ci, true);
|
||||||
|
if (ci->platdata->phy_clkgate_delay_us)
|
||||||
|
usleep_range(ci->platdata->phy_clkgate_delay_us,
|
||||||
|
ci->platdata->phy_clkgate_delay_us + 50);
|
||||||
usb_phy_set_suspend(ci->usb_phy, 1);
|
usb_phy_set_suspend(ci->usb_phy, 1);
|
||||||
ci->in_lpm = true;
|
ci->in_lpm = true;
|
||||||
enable_irq(ci->irq);
|
enable_irq(ci->irq);
|
||||||
|
@ -30,7 +30,44 @@
|
|||||||
*/
|
*/
|
||||||
u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
|
u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
|
||||||
{
|
{
|
||||||
return hw_read(ci, OP_OTGSC, mask);
|
struct ci_hdrc_cable *cable;
|
||||||
|
u32 val = hw_read(ci, OP_OTGSC, mask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If using extcon framework for VBUS and/or ID signal
|
||||||
|
* detection overwrite OTGSC register value
|
||||||
|
*/
|
||||||
|
cable = &ci->platdata->vbus_extcon;
|
||||||
|
if (!IS_ERR(cable->edev)) {
|
||||||
|
if (cable->changed)
|
||||||
|
val |= OTGSC_BSVIS;
|
||||||
|
else
|
||||||
|
val &= ~OTGSC_BSVIS;
|
||||||
|
|
||||||
|
cable->changed = false;
|
||||||
|
|
||||||
|
if (cable->state)
|
||||||
|
val |= OTGSC_BSV;
|
||||||
|
else
|
||||||
|
val &= ~OTGSC_BSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
cable = &ci->platdata->id_extcon;
|
||||||
|
if (!IS_ERR(cable->edev)) {
|
||||||
|
if (cable->changed)
|
||||||
|
val |= OTGSC_IDIS;
|
||||||
|
else
|
||||||
|
val &= ~OTGSC_IDIS;
|
||||||
|
|
||||||
|
cable->changed = false;
|
||||||
|
|
||||||
|
if (cable->state)
|
||||||
|
val |= OTGSC_ID;
|
||||||
|
else
|
||||||
|
val &= ~OTGSC_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,9 +114,12 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
|
|||||||
ci_role(ci)->name, ci->roles[role]->name);
|
ci_role(ci)->name, ci->roles[role]->name);
|
||||||
|
|
||||||
ci_role_stop(ci);
|
ci_role_stop(ci);
|
||||||
/* wait vbus lower than OTGSC_BSV */
|
|
||||||
hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
|
if (role == CI_ROLE_GADGET)
|
||||||
CI_VBUS_STABLE_TIMEOUT_MS);
|
/* wait vbus lower than OTGSC_BSV */
|
||||||
|
hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
|
||||||
|
CI_VBUS_STABLE_TIMEOUT_MS);
|
||||||
|
|
||||||
ci_role_start(ci, role);
|
ci_role_start(ci, role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,14 @@
|
|||||||
|
|
||||||
#define VF610_OVER_CUR_DIS BIT(7)
|
#define VF610_OVER_CUR_DIS BIT(7)
|
||||||
|
|
||||||
|
#define MX7D_USBNC_USB_CTRL2 0x4
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
|
||||||
|
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
|
||||||
|
|
||||||
struct usbmisc_ops {
|
struct usbmisc_ops {
|
||||||
/* It's called once when probe a usb device */
|
/* It's called once when probe a usb device */
|
||||||
int (*init)(struct imx_usbmisc_data *data);
|
int (*init)(struct imx_usbmisc_data *data);
|
||||||
@ -324,6 +332,55 @@ static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int usbmisc_imx7d_set_wakeup
|
||||||
|
(struct imx_usbmisc_data *data, bool enabled)
|
||||||
|
{
|
||||||
|
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
|
||||||
|
unsigned long flags;
|
||||||
|
u32 val;
|
||||||
|
u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
|
||||||
|
MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||||
|
val = readl(usbmisc->base);
|
||||||
|
if (enabled) {
|
||||||
|
writel(val | wakeup_setting, usbmisc->base);
|
||||||
|
} else {
|
||||||
|
if (val & MX6_BM_WAKEUP_INTR)
|
||||||
|
dev_dbg(data->dev, "wakeup int\n");
|
||||||
|
writel(val & ~wakeup_setting, usbmisc->base);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usbmisc_imx7d_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);
|
||||||
|
if (data->disable_oc) {
|
||||||
|
reg = readl(usbmisc->base);
|
||||||
|
writel(reg | MX6_BM_OVER_CUR_DIS, usbmisc->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||||
|
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
|
||||||
|
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
|
||||||
|
usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||||
|
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||||
|
|
||||||
|
usbmisc_imx7d_set_wakeup(data, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct usbmisc_ops imx25_usbmisc_ops = {
|
static const struct usbmisc_ops imx25_usbmisc_ops = {
|
||||||
.init = usbmisc_imx25_init,
|
.init = usbmisc_imx25_init,
|
||||||
.post = usbmisc_imx25_post,
|
.post = usbmisc_imx25_post,
|
||||||
@ -351,6 +408,11 @@ static const struct usbmisc_ops imx6sx_usbmisc_ops = {
|
|||||||
.init = usbmisc_imx6sx_init,
|
.init = usbmisc_imx6sx_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct usbmisc_ops imx7d_usbmisc_ops = {
|
||||||
|
.init = usbmisc_imx7d_init,
|
||||||
|
.set_wakeup = usbmisc_imx7d_set_wakeup,
|
||||||
|
};
|
||||||
|
|
||||||
int imx_usbmisc_init(struct imx_usbmisc_data *data)
|
int imx_usbmisc_init(struct imx_usbmisc_data *data)
|
||||||
{
|
{
|
||||||
struct imx_usbmisc *usbmisc;
|
struct imx_usbmisc *usbmisc;
|
||||||
@ -426,6 +488,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
|
|||||||
.compatible = "fsl,imx6sx-usbmisc",
|
.compatible = "fsl,imx6sx-usbmisc",
|
||||||
.data = &imx6sx_usbmisc_ops,
|
.data = &imx6sx_usbmisc_ops,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "fsl,imx6ul-usbmisc",
|
||||||
|
.data = &imx6sx_usbmisc_ops,
|
||||||
|
},
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
|
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
|
||||||
|
@ -5,9 +5,28 @@
|
|||||||
#ifndef __LINUX_USB_CHIPIDEA_H
|
#ifndef __LINUX_USB_CHIPIDEA_H
|
||||||
#define __LINUX_USB_CHIPIDEA_H
|
#define __LINUX_USB_CHIPIDEA_H
|
||||||
|
|
||||||
|
#include <linux/extcon.h>
|
||||||
#include <linux/usb/otg.h>
|
#include <linux/usb/otg.h>
|
||||||
|
|
||||||
struct ci_hdrc;
|
struct ci_hdrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ci_hdrc_cable - structure for external connector cable state tracking
|
||||||
|
* @state: current state of the line
|
||||||
|
* @changed: set to true when extcon event happen
|
||||||
|
* @edev: device which generate events
|
||||||
|
* @ci: driver state of the chipidea device
|
||||||
|
* @nb: hold event notification callback
|
||||||
|
* @conn: used for notification registration
|
||||||
|
*/
|
||||||
|
struct ci_hdrc_cable {
|
||||||
|
bool state;
|
||||||
|
bool changed;
|
||||||
|
struct extcon_dev *edev;
|
||||||
|
struct ci_hdrc *ci;
|
||||||
|
struct notifier_block nb;
|
||||||
|
};
|
||||||
|
|
||||||
struct ci_hdrc_platform_data {
|
struct ci_hdrc_platform_data {
|
||||||
const char *name;
|
const char *name;
|
||||||
/* offset of the capability registers */
|
/* offset of the capability registers */
|
||||||
@ -48,6 +67,11 @@ struct ci_hdrc_platform_data {
|
|||||||
u32 ahb_burst_config;
|
u32 ahb_burst_config;
|
||||||
u32 tx_burst_size;
|
u32 tx_burst_size;
|
||||||
u32 rx_burst_size;
|
u32 rx_burst_size;
|
||||||
|
|
||||||
|
/* VBUS and ID signal state tracking, using extcon framework */
|
||||||
|
struct ci_hdrc_cable vbus_extcon;
|
||||||
|
struct ci_hdrc_cable id_extcon;
|
||||||
|
u32 phy_clkgate_delay_us;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default offset of capability registers */
|
/* Default offset of capability registers */
|
||||||
|
Loading…
Reference in New Issue
Block a user