diff options
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r-- | drivers/usb/chipidea/core.c | 141 |
1 files changed, 128 insertions, 13 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 74fea4fa41b1..3feebf7f31f0 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -64,6 +64,7 @@ #include <linux/of.h> #include <linux/phy.h> #include <linux/regulator/consumer.h> +#include <linux/usb/ehci_def.h> #include "ci.h" #include "udc.h" @@ -84,6 +85,8 @@ static const u8 ci_regs_nolpm[] = { [OP_USBINTR] = 0x08U, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, + [OP_TTCTRL] = 0x1CU, + [OP_BURSTSIZE] = 0x20U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0x64U, @@ -106,6 +109,8 @@ static const u8 ci_regs_lpm[] = { [OP_USBINTR] = 0x08U, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, + [OP_TTCTRL] = 0x1CU, + [OP_BURSTSIZE] = 0x20U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0xC4U, @@ -118,7 +123,7 @@ static const u8 ci_regs_lpm[] = { [OP_ENDPTCTRL] = 0xECU, }; -static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) +static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) { int i; @@ -134,7 +139,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm) ? ci_regs_lpm[OP_ENDPTCTRL] : ci_regs_nolpm[OP_ENDPTCTRL]); - return 0; } static enum ci_revision ci_get_revision(struct ci_hdrc *ci) @@ -403,6 +407,55 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) return ret; } + +/** + * ci_platform_configure: do controller configure + * @ci: the controller + * + */ +void ci_platform_configure(struct ci_hdrc *ci) +{ + bool is_device_mode, is_host_mode; + + is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC; + is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC; + + if (is_device_mode && + (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING)) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + if (is_host_mode && + (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING)) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { + if (ci->hw_bank.lpm) + hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); + else + hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); + } + + if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA) + hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA); + + hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16); + + if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST) + hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK, + ci->platdata->ahb_burst_config); + + /* override burst size, take effect only when ahb_burst_config is 0 */ + if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) { + if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST) + hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK, + ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK)); + + if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST) + hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK, + ci->platdata->rx_burst_size); + } +} + /** * hw_controller_reset: do controller reset * @ci: the controller @@ -447,16 +500,6 @@ int hw_device_reset(struct ci_hdrc *ci) ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_RESET_EVENT); - if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); - - if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { - if (ci->hw_bank.lpm) - hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); - else - hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); - } - /* USBMODE should be configured step by step */ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); @@ -469,6 +512,8 @@ int hw_device_reset(struct ci_hdrc *ci) return -ENODEV; } + ci_platform_configure(ci); + return 0; } @@ -560,6 +605,8 @@ static irqreturn_t ci_irq(int irq, void *data) static int ci_get_platdata(struct device *dev, struct ci_hdrc_platform_data *platdata) { + int ret; + if (!platdata->phy_mode) platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); @@ -588,9 +635,66 @@ static int ci_get_platdata(struct device *dev, of_usb_host_tpl_support(dev->of_node); } + if (platdata->dr_mode == USB_DR_MODE_OTG) { + /* We can support HNP and SRP of OTG 2.0 */ + platdata->ci_otg_caps.otg_rev = 0x0200; + platdata->ci_otg_caps.hnp_support = true; + platdata->ci_otg_caps.srp_support = true; + + /* Update otg capabilities by DT properties */ + ret = of_usb_update_otg_caps(dev->of_node, + &platdata->ci_otg_caps); + if (ret) + return ret; + } + if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) platdata->flags |= CI_HDRC_FORCE_FULLSPEED; + platdata->itc_setting = 1; + if (of_find_property(dev->of_node, "itc-setting", NULL)) { + ret = of_property_read_u32(dev->of_node, "itc-setting", + &platdata->itc_setting); + if (ret) { + dev_err(dev, + "failed to get itc-setting\n"); + return ret; + } + } + + if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) { + ret = of_property_read_u32(dev->of_node, "ahb-burst-config", + &platdata->ahb_burst_config); + if (ret) { + dev_err(dev, + "failed to get ahb-burst-config\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST; + } + + if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) { + ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword", + &platdata->tx_burst_size); + if (ret) { + dev_err(dev, + "failed to get tx-burst-size-dword\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST; + } + + if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) { + ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword", + &platdata->rx_burst_size); + if (ret) { + dev_err(dev, + "failed to get rx-burst-size-dword\n"); + return ret; + } + platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST; + } + return 0; } @@ -1024,7 +1128,18 @@ static struct platform_driver ci_hdrc_driver = { }, }; -module_platform_driver(ci_hdrc_driver); +static int __init ci_hdrc_platform_register(void) +{ + ci_hdrc_host_driver_init(); + return platform_driver_register(&ci_hdrc_driver); +} +module_init(ci_hdrc_platform_register); + +static void __exit ci_hdrc_platform_unregister(void) +{ + platform_driver_unregister(&ci_hdrc_driver); +} +module_exit(ci_hdrc_platform_unregister); MODULE_ALIAS("platform:ci_hdrc"); MODULE_LICENSE("GPL v2"); |