(I really struggled with where to post this. Although much work and effort went into debugging unique Z5-specific issues, this is based on prior work so I put it here instead of in "original"; also, I would be very surprised if this didn't apply cleanly and work across the entire Z5 family, not just the Compact, but it might not apply beyond the Z5 so it doesn't make sense to put it in the cross-platform forum, which means I had to pick ONE Z5 family forum to post in. I've only tested on Compact, so I guess it goes here for now.)
I am attaching a set of kernel patches that will allow Z5 users to put their phone's USB port into host mode while simultaneously also allowing the phone to take a charge. In this scenario, the USB device(s) connected to the phone are not getting power from the phone like they normally would in a standard "OTG" scenario, but are sharing with the phone whatever power source is being used to charge the phone.
Acknowledgements:
HUGE thanks...
The patches presented here are based largely off of Phoenix Wright's work.
Background:
I used a Nexus 4 for a long time, and grew accustomed to being able to do this with my Nexus thanks to @ziddey's extremely clever hack. (My personal use-case is a phone dock in my car which both charges the phone and connects it to a USB sound card, which in turn is fed into the auxiliary input of my car's stereo head unit.) In fact, the modification ziddey came up with was both so effective and minimally-invasive that the changes were -- until relatively recently -- easy to apply to just about any Snapdragon-based device (even ones with fully-functioning OTG support, which the Nexus 4 didn'thave), since many of them shared a common USB core, and thus also shared drivers.
I was disappointed to discover upon receiving my Z5 Compact that although for some odd reason that venerable old Snapdragon USB driver was enabled in Sony's kernel's build .config, it wasn't actually being used by the hardware...I patched up the kernel, compiled it, flashed it, and the behavior of the USB port didn't change. Turns out all of the more recent Snapdragons use a new USB 3/SuperSpeed-capable core by Synopsys, part of their DesignWare series, and this core uses an entirely different driver called DWC3. And unlike the older driver, this new one does not implement support for so-called USB "accessory charging adapters" or ACAs (typically vendor-proprietary powered USB hubs that do exactly what we want: charge the phone while putting it in host mode), so in-built support for ACAs couldn't be exploited in the DWC3 driver the way that it had been in the old driver.
Fortunately, @sollapse rose to meet the challenge and whipped up some basic ACA support for the DWC3 driver included in the kernel source tree for the OnePlus One. I took what was largely a re-write of this, done by @Phoenix Wright, and essentially ported that version over to the Z5 kernel while also making some other changes and additions along the way.
Use:
Disclaimer: I cannot be held responsible if any harm should come to you or your phone on account of using these software modifications.
This was developed and tested against the Sony copyleft sources for the kernel that shipped with the last release of Lollipop for the Z5 series (32.0.A.6.200). I plan to also work on versions for the Marshmallow and Nougat kernel releases as well, but wanted to start with something as close to what I was porting from as possible and just deal with one variable at a time. Chances are good that very little changed in the USB drivers in later Z5 kernels anyway. I have also to-date only tried to apply this to an otherwise stock Sony source tree, and running on the stock Sony Lollipop ROM.
This isn't how ACAs are strictly meant to work on a device that officially supports them, but when it comes to this patch, to enable or disable "ACA mode", you need to either pass a certain parameter (aca_enable, should be set to 'Y') to the driver (dwc3) at initialization (during boot / on the kernel command line, so 'dwc3.aca_enable=Y'), or toggle the parameter after boot using sysfs (e.g. 'echo N > /sys/module/dwc3/parameters/aca_enable'). For write access to sysfs, you have to be root, so keep that in mind if you have a requirement to be able to toggle this on and off without a reboot.
Enabling ACA mode merely changes the behavior of the driver when the ID pin/pin 5 on the micro-USB cable is grounded (OTG cable), which indicates to the phone that it should switch to host mode. With ACA mode enabled, it basically doesn't engage the USB host voltage bus regulator and instead activates the battery charging circuitry; however, just like "normal" USB host mode, it still requires an actual OTG cable to work, UNLIKE ziddey's original patch. What this means is that if you want to plug, say, a thumb drive into your phone without having to also supply an external power source, you need to set 'aca_enable' back to 'N' first before this will work again.
Sometimes it is not possible to use an OTG cable in certain situations; for example, there is no way I am going to first cut out and then cut open the non-OTG micro-USB plug from my $80 Proclip car mount in order to turn it into a proper OTG cable. For these situations, ziddey's ingenious idea -- borne out of necessity by the broken ID_GND detection on the Nexus 4 -- of triggering host mode based on the type of charging adapter detected by the phone is extremely useful, and so I implemented a similar feature: by additionally setting 'prop_chg_aca_enable' to 'Y', the driver will switch to USB host mode if a so-called "proprietary" charging source is detected (which is apparently what the phone interprets the voltage injected with a USB Y-cable as).
'prop_chg_aca_enable' will have no effect if 'aca_enable' is not also toggled on. I split it out into a separate option, though, because for reasons I haven't had the time to hunt down yet, the charger detection toggle seems (based on extremely limited testing) to make the use of an OTG cable less reliable...sometimes it works, sometimes it engages the host mode but not the battery charger, sometimes it does neither. So if you already use an OTG cable with your particular set-up, I recommend you leave 'prop_chg_aca_enable' off.
Finally, as most of you surely know, the Z5 series (and the Z3+/Z4 before it) introduced a new coverless micro-USB port along with a new requirement that you the user must manually initiate a scan for attached USB gadgets in order for the port to switch over to host mode; presumably they did this so that they could keep the IP68 water ingress protection rating despite the change to a coverless port. Miraculously, when aca_enable is on, because the phone is accepting a charge instead of delivering power in this scenario, there is (in theory) no additional risk from water exposure in this mode and yet you also do NOT need to hit "Detect USB Device" on your phone before you can use the USB device...as long as both external power and a USB device are present on the cable at the moment you plug it in. If you don't have a USB device plugged into your Y-cable, only power, then the device will not be detected later. If you have a need to work around this, you can set 'no_device_timeout_enable' to 'N', which will keep the host controller on-line and engaged for as long as you have a powered OTG cable plugged in.
If you want to *really* live life on the edge, you can also set the 'force_id_polling_on' parameter of the 'qpnp_smbcharger_extension' driver to 'Y' in order to completely disable the need for tapping on "Detect USB Devices" for "normal" OTG mode.
Oh, one more thing I forgot: if you are supplying power through an OTG cable (with ID pin grounded), then you need to set 'dwc3_msm.force_float_on_bsv=N' in order to work around a change Sony made to the driver that causes it to treat powered OTG cables as if they are non-OTG. I don't know why they did this (perhaps just to further reduce the risk of water damage on account of the open port under certain circumstances?), but I added a toggle that bypasses their change.
In summary, here are all of the various driver/module options I have decided to supply to my own kernel at boot time; at a minimum #1 and #4 are mandatory when using a OTG cable and #4 and #5 are mandatory when using a non-OTG cable:
I hope others find this useful, while at the same time I also hope that our USB-C future will eventually end the need for us to dabble in such hackery.
-- Nathan
I am attaching a set of kernel patches that will allow Z5 users to put their phone's USB port into host mode while simultaneously also allowing the phone to take a charge. In this scenario, the USB device(s) connected to the phone are not getting power from the phone like they normally would in a standard "OTG" scenario, but are sharing with the phone whatever power source is being used to charge the phone.
Acknowledgements:
HUGE thanks...
- ...to @ziddey for his original patch that he developed for the Nexus 4 which was the inspiration behind all of this,
- ...to @sollapse for being the first to successfully implement ACA support in the DWC3 driver,
- ...and to @Phoenix Wright for further refining that code
The patches presented here are based largely off of Phoenix Wright's work.
Background:
I used a Nexus 4 for a long time, and grew accustomed to being able to do this with my Nexus thanks to @ziddey's extremely clever hack. (My personal use-case is a phone dock in my car which both charges the phone and connects it to a USB sound card, which in turn is fed into the auxiliary input of my car's stereo head unit.) In fact, the modification ziddey came up with was both so effective and minimally-invasive that the changes were -- until relatively recently -- easy to apply to just about any Snapdragon-based device (even ones with fully-functioning OTG support, which the Nexus 4 didn'thave), since many of them shared a common USB core, and thus also shared drivers.
I was disappointed to discover upon receiving my Z5 Compact that although for some odd reason that venerable old Snapdragon USB driver was enabled in Sony's kernel's build .config, it wasn't actually being used by the hardware...I patched up the kernel, compiled it, flashed it, and the behavior of the USB port didn't change. Turns out all of the more recent Snapdragons use a new USB 3/SuperSpeed-capable core by Synopsys, part of their DesignWare series, and this core uses an entirely different driver called DWC3. And unlike the older driver, this new one does not implement support for so-called USB "accessory charging adapters" or ACAs (typically vendor-proprietary powered USB hubs that do exactly what we want: charge the phone while putting it in host mode), so in-built support for ACAs couldn't be exploited in the DWC3 driver the way that it had been in the old driver.
Fortunately, @sollapse rose to meet the challenge and whipped up some basic ACA support for the DWC3 driver included in the kernel source tree for the OnePlus One. I took what was largely a re-write of this, done by @Phoenix Wright, and essentially ported that version over to the Z5 kernel while also making some other changes and additions along the way.
Use:
Disclaimer: I cannot be held responsible if any harm should come to you or your phone on account of using these software modifications.
This was developed and tested against the Sony copyleft sources for the kernel that shipped with the last release of Lollipop for the Z5 series (32.0.A.6.200). I plan to also work on versions for the Marshmallow and Nougat kernel releases as well, but wanted to start with something as close to what I was porting from as possible and just deal with one variable at a time. Chances are good that very little changed in the USB drivers in later Z5 kernels anyway. I have also to-date only tried to apply this to an otherwise stock Sony source tree, and running on the stock Sony Lollipop ROM.
This isn't how ACAs are strictly meant to work on a device that officially supports them, but when it comes to this patch, to enable or disable "ACA mode", you need to either pass a certain parameter (aca_enable, should be set to 'Y') to the driver (dwc3) at initialization (during boot / on the kernel command line, so 'dwc3.aca_enable=Y'), or toggle the parameter after boot using sysfs (e.g. 'echo N > /sys/module/dwc3/parameters/aca_enable'). For write access to sysfs, you have to be root, so keep that in mind if you have a requirement to be able to toggle this on and off without a reboot.
Enabling ACA mode merely changes the behavior of the driver when the ID pin/pin 5 on the micro-USB cable is grounded (OTG cable), which indicates to the phone that it should switch to host mode. With ACA mode enabled, it basically doesn't engage the USB host voltage bus regulator and instead activates the battery charging circuitry; however, just like "normal" USB host mode, it still requires an actual OTG cable to work, UNLIKE ziddey's original patch. What this means is that if you want to plug, say, a thumb drive into your phone without having to also supply an external power source, you need to set 'aca_enable' back to 'N' first before this will work again.
Sometimes it is not possible to use an OTG cable in certain situations; for example, there is no way I am going to first cut out and then cut open the non-OTG micro-USB plug from my $80 Proclip car mount in order to turn it into a proper OTG cable. For these situations, ziddey's ingenious idea -- borne out of necessity by the broken ID_GND detection on the Nexus 4 -- of triggering host mode based on the type of charging adapter detected by the phone is extremely useful, and so I implemented a similar feature: by additionally setting 'prop_chg_aca_enable' to 'Y', the driver will switch to USB host mode if a so-called "proprietary" charging source is detected (which is apparently what the phone interprets the voltage injected with a USB Y-cable as).
'prop_chg_aca_enable' will have no effect if 'aca_enable' is not also toggled on. I split it out into a separate option, though, because for reasons I haven't had the time to hunt down yet, the charger detection toggle seems (based on extremely limited testing) to make the use of an OTG cable less reliable...sometimes it works, sometimes it engages the host mode but not the battery charger, sometimes it does neither. So if you already use an OTG cable with your particular set-up, I recommend you leave 'prop_chg_aca_enable' off.
Finally, as most of you surely know, the Z5 series (and the Z3+/Z4 before it) introduced a new coverless micro-USB port along with a new requirement that you the user must manually initiate a scan for attached USB gadgets in order for the port to switch over to host mode; presumably they did this so that they could keep the IP68 water ingress protection rating despite the change to a coverless port. Miraculously, when aca_enable is on, because the phone is accepting a charge instead of delivering power in this scenario, there is (in theory) no additional risk from water exposure in this mode and yet you also do NOT need to hit "Detect USB Device" on your phone before you can use the USB device...as long as both external power and a USB device are present on the cable at the moment you plug it in. If you don't have a USB device plugged into your Y-cable, only power, then the device will not be detected later. If you have a need to work around this, you can set 'no_device_timeout_enable' to 'N', which will keep the host controller on-line and engaged for as long as you have a powered OTG cable plugged in.
If you want to *really* live life on the edge, you can also set the 'force_id_polling_on' parameter of the 'qpnp_smbcharger_extension' driver to 'Y' in order to completely disable the need for tapping on "Detect USB Devices" for "normal" OTG mode.
Oh, one more thing I forgot: if you are supplying power through an OTG cable (with ID pin grounded), then you need to set 'dwc3_msm.force_float_on_bsv=N' in order to work around a change Sony made to the driver that causes it to treat powered OTG cables as if they are non-OTG. I don't know why they did this (perhaps just to further reduce the risk of water damage on account of the open port under certain circumstances?), but I added a toggle that bypasses their change.
In summary, here are all of the various driver/module options I have decided to supply to my own kernel at boot time; at a minimum #1 and #4 are mandatory when using a OTG cable and #4 and #5 are mandatory when using a non-OTG cable:
- dwc3_msm.force_float_on_bsv=N
(disables Sony "innovation" that prevents a powered OTG cable from switching controller into host mode) - qpnp_smbcharger_extension.force_id_polling_on=Y
(disables the need for "Detect USB Devices" under normal OTG use -- NOTE this could reduce the integrity of the water protection!! Use with caution!) - dwc3.no_device_timeout_enable=N
(disables host mode timeout in the event controller does not detect a device) - dwc3.aca_enable=Y
(enables the new "ACA mode" which allows for the exclusive use of powered OTG cables at the expense of normal OTG use) - dwc3.prop_chg_aca_enable=Y
(additionally allows USB host mode to be triggered by a non-OTG powered Y-cable that also has a USB device attached)
I hope others find this useful, while at the same time I also hope that our USB-C future will eventually end the need for us to dabble in such hackery.
-- Nathan
Attachments
Last edited: