Re: [PATCH v3 1/3] usb: xhci-mtk: add generic compatible string
On 30.08.2017 14:34, Chunfeng Yun wrote: The xhci-mtk driver is a generic driver for MediaTek xHCI IP, add a generic compatible to avoid confusion when support new SoCs but use a compatible with specific SoC's name "mt8173". Signed-off-by: Chunfeng Yun --- drivers/usb/host/xhci-mtk.c |1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 67d5dc7..8fb6065 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -795,6 +795,7 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) #ifdef CONFIG_OF static const struct of_device_id mtk_xhci_of_match[] = { { .compatible = "mediatek,mt8173-xhci"}, + { .compatible = "mediatek,mtk-xhci"}, { }, }; MODULE_DEVICE_TABLE(of, mtk_xhci_of_match); Acked-by: Mathias Nyman -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] usb: pci-quirks.c: Corrected timeout values used in handshake
On 01.09.2017 09:21, Felipe Balbi wrote: Hi, Jim Dickerson writes: Servers were emitting failed handoff messages but were not waiting the full 1 second as designated in section 4.22.1 of the eXtensible Host Controller Interface specifications. The handshake was using wrong units so calls were made with milliseconds not microseconds. Comments referenced 5 seconds not 1 second as in specs. The wrong units were also corrected in a second handshake call. Signed-off-by: Jim Dickerson --- drivers/usb/host/pci-quirks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c8f3864..abc9436 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -1068,9 +1068,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev) if (val & XHCI_HC_BIOS_OWNED) { writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset); - /* Wait for 5 seconds with 10 microsecond polling interval */ + /* Wait for 1 seconds with 10 microsecond polling interval */ ^^^ second Applying, I'll fix the typo myself, don't worry about it Thanks -Mathias -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[GIT PULL] USB-serial updates for v4.14-rc1
The following changes since commit ef954844c7ace62f773f4f23e28d2d915adc419f: Linux 4.13-rc5 (2017-08-13 16:01:32 -0700) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git tags/usb-serial-4.14-rc1 for you to fetch changes up to b5fdde28d4b7731554dc9bdeab529fcddd6ba4c7: USB: serial: option: simplify 3 D-Link device entries (2017-08-30 09:41:25 +0200) USB-serial updates for v4.14-rc1 Here are the USB-serial updates for 4.14-rc1; a new option device id and one device-id clean up. All have been in linux-next with no reported issues. Signed-off-by: Johan Hovold Bjørn Mork (1): USB: serial: option: simplify 3 D-Link device entries Maciej S. Szmigiero (1): USB: serial: option: add support for D-Link DWM-157 C1 drivers/usb/serial/option.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
kernel-stable upgrade from 4.12.7 -> 4.12.[8,9,10] causes USB device failures on some machines; OK with 4.13.0rc
(apprently didn't post; take 2) Upgrading from a working linux64 kernel-default 4.12.7x instance to -> kernel-default 4.12.8x breaks USB devices (non-responsive) on AMD SB700 motherboards. I reported @ distro Bug 1055044 - kernel-stable upgrade from 4.12.7 -> 4.12.[8,9,10] causes USB device failures on some machines; fix re: AMD freeze workaround; OK with 4.13.0rc6 https://bugzilla.opensuse.org/show_bug.cgi?id=1055044#c7 There, demonstrated that it's related to a years-old patch, but did not yet determine WHY it cropped up again in 4.12.x branch. Moving to v4.13.0rc6 cures the problem. Response at the bug's gone silent. As I'm unclear whether the fortuitous, unknown fix in 4.13.0 is sufficient here, or whether it needs to be found/verified in 4.12.x so as not to propagate into 4.13, thought best to bring it up here ... b4 release. Can someone take a look & opine about a fix for 4.12 stable branch? Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [GIT PULL] USB-serial updates for v4.14-rc1
On Fri, Sep 01, 2017 at 04:11:36PM +0200, Johan Hovold wrote: > The following changes since commit ef954844c7ace62f773f4f23e28d2d915adc419f: > > Linux 4.13-rc5 (2017-08-13 16:01:32 -0700) > > are available in the git repository at: > > git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git > tags/usb-serial-4.14-rc1 Pulled and pushed out, thanks. greg k-h -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCHv2 1/7] dt-bindings: usb: Document the STM32F7 DWC2 USB OTG HS core binding
On Mon, Aug 28, 2017 at 04:20:12PM +0200, Amelie Delaunay wrote: > This patch adds binding documentation for DWC2 controller in HS mode found > on STMicroelectronics STM32F7 SoC. > > Signed-off-by: Amelie Delaunay > --- > Documentation/devicetree/bindings/usb/dwc2.txt | 2 ++ > 1 file changed, 2 insertions(+) Acked-by: Rob Herring -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] usb: gadget: configfs: Fix KASAN use-after-free
On Tue, Jan 17, 2017 at 1:29 AM, Jim Lin wrote: > When gadget is disconnected, running sequence is like this. > . composite_disconnect > . Call trace: > usb_string_copy+0xd0/0x128 > gadget_config_name_configuration_store+0x4 > gadget_config_name_attr_store+0x40/0x50 > configfs_write_file+0x198/0x1f4 > vfs_write+0x100/0x220 > SyS_write+0x58/0xa8 > . configfs_composite_unbind > . configfs_composite_bind > > In configfs_composite_bind, it has > "cn->strings.s = cn->configuration;" > > When usb_string_copy is invoked. it would > allocate memory, copy input string, release previous pointed memory space, > and use new allocated memory. > > When gadget is connected, host sends down request to get information. > Call trace: > usb_gadget_get_string+0xec/0x168 > lookup_string+0x64/0x98 > composite_setup+0xa34/0x1ee8 > android_setup+0xb4/0x140 > > If gadget is disconnected and connected quickly, in the failed case, > cn->configuration memory has been released by usb_string_copy kfree but > configfs_composite_bind hasn't been run in time to assign new allocated > "cn->configuration" pointer to "cn->strings.s". > > When "strlen(s->s) of usb_gadget_get_string is being executed, the dangling > memory is accessed, "BUG: KASAN: use-after-free" error occurs. > > Signed-off-by: Jim Lin Hi! What's the current state of this patch? > --- > Changes in v2: > Rephrase commit description > > drivers/usb/gadget/configfs.c | 15 +++ > 1 file changed, 11 insertions(+), 4 deletions(-) > > diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c > index 78c4497..39fea62 100644 > --- a/drivers/usb/gadget/configfs.c > +++ b/drivers/usb/gadget/configfs.c > @@ -106,6 +106,9 @@ struct gadget_config_name { > struct list_head list; > }; > > +#define MAX_USB_STRING_LEN 126 > +#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1) > + > static int usb_string_copy(const char *s, char **s_copy) > { > int ret; > @@ -115,12 +118,16 @@ static int usb_string_copy(const char *s, char **s_copy) > if (ret > 126) This should be MAX_USB_STRING_LEN, yes? > return -EOVERFLOW; > > - str = kstrdup(s, GFP_KERNEL); > - if (!str) > - return -ENOMEM; > + if (copy) { > + str = copy; > + } else { > + str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL); > + if (!str) > + return -ENOMEM; > + } > + strcpy(str, s); > if (str[ret - 1] == '\n') > str[ret - 1] = '\0'; > - kfree(copy); > *s_copy = str; > return 0; > } > -- > 2.7.4 > -Kees -- Kees Cook Pixel Security -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling
The Intel cherrytrail xhci controller has an extended cap mmio-range which contains registers to control the muxing to the xhci (host mode) or the dwc3 (device mode) and vbus-detection for the otg usb-phy. Having a mux driver included in the xhci code (or under drivers/usb/host) is not desirable. So this commit adds a simple handler for this extended capability, which creates a platform device with the caps mmio region as resource, this allows us to write a separate platform mux driver for the mux. Signed-off-by: Hans de Goede --- Changes in v2: -Check xHCI controller PCI device-id instead of only checking for the Intel Extended capability ID, as the Extended capability ID is used on other model Intel xHCI controllers too --- drivers/usb/host/Makefile| 2 +- drivers/usb/host/xhci-intel-quirks.c | 85 drivers/usb/host/xhci-pci.c | 4 ++ drivers/usb/host/xhci.h | 2 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/host/xhci-intel-quirks.c diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index cf2691fffcc0..441edf82eb1c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -63,7 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_DAVINCI)+= ohci-da8xx.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o -obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o +obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o xhci-intel-quirks.o obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o diff --git a/drivers/usb/host/xhci-intel-quirks.c b/drivers/usb/host/xhci-intel-quirks.c new file mode 100644 index ..819f5f9da9ee --- /dev/null +++ b/drivers/usb/host/xhci-intel-quirks.c @@ -0,0 +1,85 @@ +/* + * Intel Vendor Defined XHCI extended capability handling + * + * Copyright (c) 2016) Hans de Goede + * + * Loosely based on android x86 kernel code which is: + * + * Copyright (C) 2014 Intel Corp. + * + * Author: Wu, Hao + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; + */ + +#include +#include "xhci.h" + +/* Extended capability IDs for Intel Vendor Defined */ +#define XHCI_EXT_CAPS_INTEL_HOST_CAP 192 + +static void xhci_intel_unregister_pdev(void *arg) +{ + platform_device_unregister(arg); +} + +int xhci_create_intel_cht_mux_pdev(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct device *dev = hcd->self.controller; + struct platform_device *pdev; + struct resource res = { 0, }; + int ret, ext_offset; + + ext_offset = xhci_find_next_ext_cap(&xhci->cap_regs->hc_capbase, 0, + XHCI_EXT_CAPS_INTEL_HOST_CAP); + if (!ext_offset) { + xhci_err(xhci, "couldn't find Intel ext caps\n"); + return -ENODEV; + } + + pdev = platform_device_alloc("intel_cht_usb_mux", PLATFORM_DEVID_NONE); + if (!pdev) { + xhci_err(xhci, "couldn't allocate intel_cht_usb_mux pdev\n"); + return -ENOMEM; + } + + res.start = hcd->rsrc_start + ext_offset; + res.end = res.start + 0x3ff; + res.name = "intel_cht_usb_mux"; + res.flags = IORESOURCE_MEM; + + ret = platform_device_add_resources(pdev, &res, 1); + if (ret) { + dev_err(dev, "couldn't add resources to intel_cht_usb_mux pdev\n"); + platform_device_put(pdev); + return ret; + } + + pdev->dev.parent = dev; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(dev, "couldn't register intel_cht_usb_mux pdev\n"); + platform_device_put(pdev); + return ret; + } + + ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev); + if (ret) { + dev_err(dev, "couldn't add unregister action for intel_cht_usb_mux pdev\n"); + return ret; + } + + return 0; +} diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 8071c8fdd15e..b55c1e96abf0 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -188,6 +188,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_
[PATCH 11/11] platform/x86: intel_cht_int33fe: Add mux mappings for the Type-C port
We need to add mappings for the mux subsys to be able to find the muxes for the fusb302 driver to be able to control the PI3USB30532 Type-C mux and the device/host mux integrated in the CHT SoC. Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/intel_cht_int33fe.c | 23 +++ 2 files changed, 24 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c5554577681a..4256e05ee584 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -794,6 +794,7 @@ config ACPI_CMPC config INTEL_CHT_INT33FE tristate "Intel Cherry Trail ACPI INT33FE Driver" depends on X86 && ACPI && I2C && REGULATOR + select MULTIPLEXER ---help--- This driver add support for the INT33FE ACPI device found on some Intel Cherry Trail devices. diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c index 24a1662be81d..611b8af9cefd 100644 --- a/drivers/platform/x86/intel_cht_int33fe.c +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,19 @@ struct cht_int33fe_data { struct i2c_client *pi3usb30532; }; +static struct mux_lookup cht_int33fe_mux_lookup[] = { + { + .provider = "i2c-pi3usb30532", + .dev_id = "i2c-fusb302", + .mux_name = "type-c-mode-mux", + }, + { + .provider = "intel_cht_usb_mux", + .dev_id = "i2c-fusb302", + .mux_name = "usb-role-mux", + }, +}; + /* * Grrr I severly dislike buggy BIOS-es. At least one BIOS enumerates * the max17047 both through the INT33FE ACPI device (it is right there @@ -170,6 +184,9 @@ static int cht_int33fe_probe(struct i2c_client *client) board_info.properties = fusb302_props; board_info.irq = fusb302_irq; + mux_add_table(cht_int33fe_mux_lookup, + ARRAY_SIZE(cht_int33fe_mux_lookup)); + data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); if (!data->fusb302) goto out_unregister_max17047; @@ -193,6 +210,9 @@ static int cht_int33fe_probe(struct i2c_client *client) if (data->max17047) i2c_unregister_device(data->max17047); + mux_remove_table(cht_int33fe_mux_lookup, + ARRAY_SIZE(cht_int33fe_mux_lookup)); + return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ } @@ -205,6 +225,9 @@ static int cht_int33fe_remove(struct i2c_client *i2c) if (data->max17047) i2c_unregister_device(data->max17047); + mux_remove_table(cht_int33fe_mux_lookup, + ARRAY_SIZE(cht_int33fe_mux_lookup)); + return 0; } -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/11] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support
Add mux support to the fusb302 driver, call devm_tcpc_gen_mux_create() to let the generic tcpc_mux_dev code create a tcpc_mux_dev for us. Also document the mux-names used by the generic tcpc_mux_dev code in our devicetree bindings. Cc: Rob Herring Cc: Mark Rutland Cc: devicet...@vger.kernel.org Signed-off-by: Hans de Goede --- Documentation/devicetree/bindings/usb/fcs,fusb302.txt | 3 +++ drivers/staging/typec/fusb302/fusb302.c | 11 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt index 472facfa5a71..63d639eadacd 100644 --- a/Documentation/devicetree/bindings/usb/fcs,fusb302.txt +++ b/Documentation/devicetree/bindings/usb/fcs,fusb302.txt @@ -6,6 +6,9 @@ Required properties : - interrupts : Interrupt specifier Optional properties : +- mux-controls : List of mux-ctrl-specifiers containing 1 or 2 muxes +- mux-names : "type-c-mode-mux" when using 1 mux, or + "type-c-mode-mux", "usb-role-mux" when using 2 muxes - fcs,max-sink-microvolt : Maximum voltage to negotiate when configured as sink - fcs,max-sink-microamp : Maximum current to negotiate when configured as sink - fcs,max-sink-microwatt : Maximum power to negotiate when configured as sink diff --git a/drivers/staging/typec/fusb302/fusb302.c b/drivers/staging/typec/fusb302/fusb302.c index cf6355f59cd9..00d045d0246b 100644 --- a/drivers/staging/typec/fusb302/fusb302.c +++ b/drivers/staging/typec/fusb302/fusb302.c @@ -1259,7 +1259,6 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev) fusb302_tcpc_dev->set_roles = tcpm_set_roles; fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling; fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit; - fusb302_tcpc_dev->mux = NULL; } static const char * const cc_polarity_name[] = { @@ -1817,6 +1816,16 @@ static int fusb302_probe(struct i2c_client *client, return -EPROBE_DEFER; } + chip->tcpc_dev.mux = devm_tcpc_gen_mux_create(dev); + if (IS_ERR(chip->tcpc_dev.mux)) { + ret = PTR_ERR(chip->tcpc_dev.mux); + /* Use of a mux is optional (for now?), ignore -ENODEV errors */ + if (ret == -ENODEV) + chip->tcpc_dev.mux = NULL; + else + return ret; + } + cfg.drv_data = chip; chip->psy = devm_power_supply_register(dev, &fusb302_psy_desc, &cfg); if (IS_ERR(chip->psy)) { -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 09/11] staging: typec: Add Generic TCPC mux driver using the mux subsys
So far the mux functionality of the tcpm code has not been hooked up in any tcpc drivers. This commit adds a generic TCPC mux driver using the mux subsys, which tcpc drivers can use to provide mux functionality in cases where an external my is used. Signed-off-by: Hans de Goede --- drivers/staging/typec/Makefile | 2 +- drivers/staging/typec/tcpc_gen_mux.c | 129 +++ drivers/staging/typec/tcpm.h | 2 + 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/typec/tcpc_gen_mux.c diff --git a/drivers/staging/typec/Makefile b/drivers/staging/typec/Makefile index 30a7e29cbc9e..623d78114ee3 100644 --- a/drivers/staging/typec/Makefile +++ b/drivers/staging/typec/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_TYPEC_TCPM) += tcpm.o +obj-$(CONFIG_TYPEC_TCPM) += tcpm.o tcpc_gen_mux.o obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o obj-y += fusb302/ diff --git a/drivers/staging/typec/tcpc_gen_mux.c b/drivers/staging/typec/tcpc_gen_mux.c new file mode 100644 index ..dc725e17b106 --- /dev/null +++ b/drivers/staging/typec/tcpc_gen_mux.c @@ -0,0 +1,129 @@ +/* + * Generic TCPC mux driver using the mux subsys + * + * Copyright (c) 2017 Hans de Goede + * + * 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, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include "tcpm.h" + +struct tcpc_gen_mux_data { + struct tcpc_mux_dev mux; + struct device *dev; + struct mux_control *type_c_mode_mux; /* Type-C cross switch / mux */ + struct mux_control *usb_role_mux;/* USB Device / Host mode mux */ + bool muxes_set; +}; + +static int tcpc_gen_mux_set(struct tcpc_mux_dev *mux_dev, + enum tcpc_mux_mode mux_mode, + enum tcpc_usb_switch usb_config, + enum typec_cc_polarity polarity) +{ + struct tcpc_gen_mux_data *data = + container_of(mux_dev, struct tcpc_gen_mux_data, mux); + unsigned int state = MUX_USB_NONE; + int ret; + + switch (mux_mode) { + case TYPEC_MUX_NONE: + state = MUX_USB_NONE; + break; + case TYPEC_MUX_USB_DEVICE: + state = MUX_USB_DEVICE; + break; + case TYPEC_MUX_USB_HOST: + state = MUX_USB_HOST; + break; + case TYPEC_MUX_DP: + state = MUX_USB_DP_SRC; + break; + case TYPEC_MUX_DOCK: + state = MUX_USB_HOST_AND_DP_SRC; + break; + } + + if (polarity) + state |= MUX_USB_POLARITY_INV; + + /* +* The mux framework expects multiple competing users, so we must +* release our previous setting before applying the new one. +*/ + if (data->muxes_set) { + mux_control_deselect(data->type_c_mode_mux); + if (data->usb_role_mux) + mux_control_deselect(data->usb_role_mux); + data->muxes_set = false; + } + + ret = mux_control_select(data->type_c_mode_mux, state); + if (ret) { + dev_err(data->dev, "Error setting Type-C mode mux: %d\n", ret); + return ret; + } + + if (!data->usb_role_mux) + goto out; + + ret = mux_control_select(data->usb_role_mux, state); + if (ret) { + dev_err(data->dev, "Error setting USB role mux: %d\n", ret); + mux_control_deselect(data->type_c_mode_mux); + return ret; + } + +out: + data->muxes_set = true; + return 0; +} + +struct tcpc_mux_dev *devm_tcpc_gen_mux_create(struct device *dev) +{ + struct tcpc_gen_mux_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + data->type_c_mode_mux = devm_mux_control_get(dev, "type-c-mode-mux"); + if (IS_ERR(data->type_c_mode_mux)) { + ret = PTR_ERR(data->type_c_mode_mux); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error getting Type-C mux: %d\n", ret); + return ERR_PTR(-ret); + } + + data->usb_role_mux = devm_mux_control_get(dev, "usb-role-mux"); + if (IS_ERR(data->usb_role_mux)) { + ret = PTR_ERR(data->usb_role_mux); + /* The USB role mux is optional */ + if (ret == -ENODEV) { + data->usb_role_mux = NULL; + } else { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Error getting USB role mux: %d\n", + ret); + return ERR_PTR(
[PATCH 07/11] extcon: intel-int3496: Add support for controlling the USB-role mux
Cherry Trail SoCs have a built-in USB-role mux for switching between the host and device controllers, rather then using an external mux controller by a GPIO. There is a driver using the mux-subsys to control this mux, this commit adds support to the intel-int3496 driver to get a mux_controller handle for the mux and set the mux through the mux-subsys rather then through a GPIO. Signed-off-by: Hans de Goede --- drivers/extcon/Kconfig| 1 + drivers/extcon/extcon-intel-int3496.c | 59 ++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index a7bca4207f44..7ab6acc9708a 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -45,6 +45,7 @@ config EXTCON_GPIO config EXTCON_INTEL_INT3496 tristate "Intel INT3496 ACPI device extcon driver" depends on GPIOLIB && ACPI && (X86 || COMPILE_TEST) + select MULTIPLEXER help Say Y here to enable extcon support for USB OTG ports controlled by an Intel INT3496 ACPI device. diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index 1a45e745717d..cea9c9b1521c 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -23,8 +23,12 @@ #include #include #include +#include #include +#include +#include + #define INT3496_GPIO_USB_ID0 #define INT3496_GPIO_VBUS_EN 1 #define INT3496_GPIO_USB_MUX 2 @@ -37,6 +41,8 @@ struct int3496_data { struct gpio_desc *gpio_usb_id; struct gpio_desc *gpio_vbus_en; struct gpio_desc *gpio_usb_mux; + struct mux_control *usb_mux; + bool usb_mux_set; int usb_id_irq; }; @@ -56,11 +62,31 @@ static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = { { }, }; +static struct mux_lookup acpi_int3496_cht_mux_lookup[] = { + { + .provider = "intel_cht_usb_mux", + .dev_id = "INT3496:00", + .mux_name = "usb-role-mux", + }, +}; + +#define ICPU(model){ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +static const struct x86_cpu_id cht_cpu_ids[] = { + ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ + {} +}; + +static bool int3496_soc_has_mux(void) +{ + return x86_match_cpu(cht_cpu_ids); +} + static void int3496_do_usb_id(struct work_struct *work) { struct int3496_data *data = container_of(work, struct int3496_data, work.work); - int id = gpiod_get_value_cansleep(data->gpio_usb_id); + int ret, id = gpiod_get_value_cansleep(data->gpio_usb_id); /* id == 1: PERIPHERAL, id == 0: HOST */ dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST"); @@ -72,6 +98,22 @@ static void int3496_do_usb_id(struct work_struct *work) if (!IS_ERR(data->gpio_usb_mux)) gpiod_direction_output(data->gpio_usb_mux, id); + if (data->usb_mux) { + /* +* The mux framework expects multiple competing users, we must +* release our previous setting before applying the new one. +*/ + if (data->usb_mux_set) + mux_control_deselect(data->usb_mux); + + ret = mux_control_select(data->usb_mux, +id ? MUX_USB_DEVICE : MUX_USB_HOST); + if (ret) + dev_err(data->dev, "Error setting mux: %d\n", ret); + + data->usb_mux_set = ret == 0; + } + if (!IS_ERR(data->gpio_vbus_en)) gpiod_direction_output(data->gpio_vbus_en, !id); @@ -107,6 +149,21 @@ static int int3496_probe(struct platform_device *pdev) data->dev = dev; INIT_DELAYED_WORK(&data->work, int3496_do_usb_id); + if (int3496_soc_has_mux()) { + mux_add_table(acpi_int3496_cht_mux_lookup, + ARRAY_SIZE(acpi_int3496_cht_mux_lookup)); + data->usb_mux = devm_mux_control_get(dev, "usb-role-mux"); + /* Doing this here keeps our error handling clean. */ + mux_remove_table(acpi_int3496_cht_mux_lookup, +ARRAY_SIZE(acpi_int3496_cht_mux_lookup)); + if (IS_ERR(data->usb_mux)) { + ret = PTR_ERR(data->usb_mux); + if (ret != -EPROBE_DEFER) + dev_err(dev, "can't get mux: %d\n", ret); + return ret; + } + } + data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN); if (IS_ERR(data->gpio_usb_id)) { ret = PTR_ERR(data->gpio_usb_id); -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-
[PATCH 08/11] staging: typec: tcpm: Set mux to device mode when configured as such
Setting the mux to TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT when the data-role is device is not correct. Plenty of devices support operating as USB device through a (separate) USB device controller. So this commit instead splits out TYPEC_MUX_USB into TYPEC_MUX_USB_HOST and TYPEC_MUX_USB_DEVICE and makes tcpm_set_roles() set the mux accordingly. Likewise TCPC_MUX_DP gets renamed to TCPC_MUX_DP_SRC to make clear that this is for configuring the Type-C port as a Display Port source, not a sink. Last this commit makes tcpm_reset_port() to set the mux to TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT so that it does not and up staying in host (and with this commit also device) mode after a detach. Signed-off-by: Hans de Goede --- drivers/staging/typec/tcpm.c | 7 --- drivers/staging/typec/tcpm.h | 22 ++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c index 8af62e74d54c..ffe7e26d4ed3 100644 --- a/drivers/staging/typec/tcpm.c +++ b/drivers/staging/typec/tcpm.c @@ -752,11 +752,11 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached, int ret; if (data == TYPEC_HOST) - ret = tcpm_mux_set(port, TYPEC_MUX_USB, + ret = tcpm_mux_set(port, TYPEC_MUX_USB_HOST, TCPC_USB_SWITCH_CONNECT); else - ret = tcpm_mux_set(port, TYPEC_MUX_NONE, - TCPC_USB_SWITCH_DISCONNECT); + ret = tcpm_mux_set(port, TYPEC_MUX_USB_DEVICE, + TCPC_USB_SWITCH_CONNECT); if (ret < 0) return ret; @@ -2025,6 +2025,7 @@ static void tcpm_reset_port(struct tcpm_port *port) tcpm_init_vconn(port); tcpm_set_current_limit(port, 0, 0); tcpm_set_polarity(port, TYPEC_POLARITY_CC1); + tcpm_mux_set(port, TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT); tcpm_set_attached_state(port, false); port->try_src_count = 0; port->try_snk_count = 0; diff --git a/drivers/staging/typec/tcpm.h b/drivers/staging/typec/tcpm.h index 7e9a6b7b5cd6..f662eed48c86 100644 --- a/drivers/staging/typec/tcpm.h +++ b/drivers/staging/typec/tcpm.h @@ -83,17 +83,23 @@ enum tcpc_usb_switch { }; /* Mux state attributes */ -#define TCPC_MUX_USB_ENABLED BIT(0) /* USB enabled */ -#define TCPC_MUX_DP_ENABLEDBIT(1) /* DP enabled */ -#define TCPC_MUX_POLARITY_INVERTED BIT(2) /* Polarity inverted */ +#define TCPC_MUX_USB_DEVICE_ENABLEDBIT(0) /* USB device enabled */ +#define TCPC_MUX_USB_HOST_ENABLED BIT(1) /* USB host enabled */ +#define TCPC_MUX_DP_SRC_ENABLEDBIT(2) /* DP enabled */ +#define TCPC_MUX_POLARITY_INVERTED BIT(3) /* Polarity inverted */ /* Mux modes, decoded to attributes */ enum tcpc_mux_mode { - TYPEC_MUX_NONE = 0,/* Open switch */ - TYPEC_MUX_USB = TCPC_MUX_USB_ENABLED, /* USB only */ - TYPEC_MUX_DP= TCPC_MUX_DP_ENABLED, /* DP only */ - TYPEC_MUX_DOCK = TCPC_MUX_USB_ENABLED |/* Both USB and DP */ - TCPC_MUX_DP_ENABLED, + /* Open switch */ + TYPEC_MUX_NONE = 0, + /* USB device only */ + TYPEC_MUX_USB_DEVICE = TCPC_MUX_USB_DEVICE_ENABLED, + /* USB host only */ + TYPEC_MUX_USB_HOST = TCPC_MUX_USB_HOST_ENABLED, + /* DP source only */ + TYPEC_MUX_DP = TCPC_MUX_DP_SRC_ENABLED, + /* Both USB host and DP source */ + TYPEC_MUX_DOCK = TCPC_MUX_USB_HOST_ENABLED | TCPC_MUX_DP_SRC_ENABLED, }; struct tcpc_mux_dev { -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/11] mux: Add Pericom PI3USB30532 Type-C mux driver
Add a driver for the Pericom PI3USB30532 Type-C cross switch / mux chip found on some devices with a Type-C port. Signed-off-by: Hans de Goede --- drivers/mux/Kconfig | 10 + drivers/mux/Makefile | 2 + drivers/mux/pi3usb30532.c | 97 +++ 3 files changed, 109 insertions(+) create mode 100644 drivers/mux/pi3usb30532.c diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig index 17938918bf93..19a3065c34e6 100644 --- a/drivers/mux/Kconfig +++ b/drivers/mux/Kconfig @@ -58,4 +58,14 @@ config MUX_MMIO To compile the driver as a module, choose M here: the module will be called mux-mmio. +config MUX_PI3USB30532 + tristate "Pericom PI3USB30532 Type-C cross switch driver" + depends on I2C + help + This driver adds support for the Pericom PI3USB30532 Type-C cross + switch / mux chip found on some devices with a Type-C port. + + To compile the driver as a module, choose M here: the module will + be called mux-pi3usb30532. + endmenu diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile index a12e812c7966..7563dbf04593 100644 --- a/drivers/mux/Makefile +++ b/drivers/mux/Makefile @@ -7,9 +7,11 @@ mux-adg792a-objs := adg792a.o mux-gpio-objs := gpio.o mux-mmio-objs := mmio.o mux-intel_cht_usb_mux-objs := intel_cht_usb_mux.o +mux-pi3usb30532-objs := pi3usb30532.o obj-$(CONFIG_MULTIPLEXER) += mux-core.o obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o obj-$(CONFIG_MUX_GPIO) += mux-gpio.o obj-$(CONFIG_MUX_MMIO) += mux-mmio.o obj-$(CONFIG_MUX_CHT_USB_MUX) += mux-intel_cht_usb_mux.o +obj-$(CONFIG_MUX_PI3USB30532) += mux-pi3usb30532.o diff --git a/drivers/mux/pi3usb30532.c b/drivers/mux/pi3usb30532.c new file mode 100644 index ..fa8abd851520 --- /dev/null +++ b/drivers/mux/pi3usb30532.c @@ -0,0 +1,97 @@ +/* + * Pericom PI3USB30532 Type-C cross switch / mux driver + * + * Copyright (c) 2017 Hans de Goede + * + * 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, or (at your option) + * any later version. + */ + +#include +#include +#include +#include /* For the MUX_USB_* defines */ +#include + +#define PI3USB30532_CONF 0x00 + +#define PI3USB30532_CONF_OPEN 0x00 +#define PI3USB30532_CONF_SWAP 0x01 +#define PI3USB30532_CONF_4LANE_DP 0x02 +#define PI3USB30532_CONF_USB3 0x04 +#define PI3USB30532_CONF_USB3_AND_2LANE_DP 0x06 + +struct pi3usb30532_mux { + struct i2c_client *client; +}; + +static int pi3usb30532_mux_set_mux(struct mux_control *mux_ctrl, int state) +{ + struct pi3usb30532_mux *mux = mux_chip_priv(mux_ctrl->chip); + u8 conf = PI3USB30532_CONF_OPEN; + + switch (state & ~MUX_USB_POLARITY_INV) { + case MUX_USB_NONE: + conf = PI3USB30532_CONF_OPEN; + break; + case MUX_USB_DEVICE: + case MUX_USB_HOST: + conf = PI3USB30532_CONF_USB3; + break; + case MUX_USB_HOST_AND_DP_SRC: + conf = PI3USB30532_CONF_USB3_AND_2LANE_DP; + break; + case MUX_USB_DP_SRC: + conf = PI3USB30532_CONF_4LANE_DP; + break; + } + + if (state & MUX_USB_POLARITY_INV) + conf |= PI3USB30532_CONF_SWAP; + + return i2c_smbus_write_byte_data(mux->client, PI3USB30532_CONF, conf); +} + +static const struct mux_control_ops pi3usb30532_mux_ops = { + .set = pi3usb30532_mux_set_mux, +}; + +static int pi3usb30532_mux_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct pi3usb30532_mux *mux; + struct mux_chip *mux_chip; + + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux)); + if (IS_ERR(mux_chip)) + return PTR_ERR(mux_chip); + + mux_chip->ops = &pi3usb30532_mux_ops; + mux_chip->mux[0].states = MUX_USB_STATES; + mux = mux_chip_priv(mux_chip); + mux->client = client; + + return devm_mux_chip_register(dev, mux_chip); +} + +static const struct i2c_device_id pi3usb30532_mux_table[] = { + { "pi3usb30532" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pi3usb30532_mux_table); + +static struct i2c_driver pi3usb30532_mux_driver = { + .driver = { + .name = "pi3usb30532", + }, + .probe_new = pi3usb30532_mux_probe, + .id_table = pi3usb30532_mux_table, +}; + +module_i2c_driver(pi3usb30532_mux_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("Pericom PI3USB30532 Type-C mux driver"); +MODULE_LICENSE("GPL"); -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo inf
[PATCH 05/11] mux: Add Intel Cherrytrail USB mux driver
Intel Cherrytrail SoCs have an internal USB mux for muxing the otg-port USB data lines between the xHCI host controller and the dwc3 gadget controller. On some Cherrytrail systems this mux is controlled through AML code reacting on a GPIO IRQ connected to the USB OTG id pin (through an _AIE ACPI method) so things just work. But on other Cherrytrail systems we need to control the mux ourselves this driver exports the mux through the mux subsys, so that other drivers can control it if necessary. This driver also updates the vbus-valid reporting to the dwc3 gadget controller, as this uses the same registers as the mux. This is needed for gadget/device mode to work properly (even on systems which control the mux from their AML code). Note this depends on the xhci driver registering a platform device named "intel_cht_usb_mux", which has an IOMEM resource 0 which points to the Intel Vendor Defined XHCI extended capabilities region. Signed-off-by: Hans de Goede --- Changes in v2: -Complete rewrite as a stand-alone platform-driver rather then as a phy driver, since this is just a mux, not a phy Changes in v3: -Make this a mux subsys driver instead of listening to USB_HOST extcon cable events and responding to those --- drivers/mux/Kconfig | 11 ++ drivers/mux/Makefile| 2 + drivers/mux/intel_cht_usb_mux.c | 269 3 files changed, 282 insertions(+) create mode 100644 drivers/mux/intel_cht_usb_mux.c diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig index 19e4e904c9bf..17938918bf93 100644 --- a/drivers/mux/Kconfig +++ b/drivers/mux/Kconfig @@ -34,6 +34,17 @@ config MUX_GPIO To compile the driver as a module, choose M here: the module will be called mux-gpio. +config MUX_CHT_USB_MUX + tristate "Intel Cherrytrail USB Multiplexer" + depends on ACPI && X86 && EXTCON + help + This driver adds support for the internal USB mux for muxing the OTG + USB data lines between the xHCI host controller and the dwc3 gadget + controller found on Intel Cherrytrail SoCs. + + To compile the driver as a module, choose M here: the module will + be called mux-intel_cht_usb_mux. + config MUX_MMIO tristate "MMIO register bitfield-controlled Multiplexer" depends on (OF && MFD_SYSCON) || COMPILE_TEST diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile index 0e1e59760e3f..a12e812c7966 100644 --- a/drivers/mux/Makefile +++ b/drivers/mux/Makefile @@ -6,8 +6,10 @@ mux-core-objs := core.o mux-adg792a-objs := adg792a.o mux-gpio-objs := gpio.o mux-mmio-objs := mmio.o +mux-intel_cht_usb_mux-objs := intel_cht_usb_mux.o obj-$(CONFIG_MULTIPLEXER) += mux-core.o obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o obj-$(CONFIG_MUX_GPIO) += mux-gpio.o obj-$(CONFIG_MUX_MMIO) += mux-mmio.o +obj-$(CONFIG_MUX_CHT_USB_MUX) += mux-intel_cht_usb_mux.o diff --git a/drivers/mux/intel_cht_usb_mux.c b/drivers/mux/intel_cht_usb_mux.c new file mode 100644 index ..7b1621a081d8 --- /dev/null +++ b/drivers/mux/intel_cht_usb_mux.c @@ -0,0 +1,269 @@ +/* + * Intel Cherrytrail USB OTG MUX driver + * + * Copyright (c) 2016 Hans de Goede + * + * Loosely based on android x86 kernel code which is: + * + * Copyright (C) 2014 Intel Corp. + * + * Author: Wu, Hao + * + * 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, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* For the MUX_USB_* defines */ +#include +#include +#include + +/* register definition */ +#define DUAL_ROLE_CFG0 0x68 +#define SW_VBUS_VALID (1 << 24) +#define SW_IDPIN_EN(1 << 21) +#define SW_IDPIN (1 << 20) + +#define DUAL_ROLE_CFG1 0x6c +#define HOST_MODE (1 << 29) + +#define DUAL_ROLE_CFG1_POLL_TIMEOUT1000 + +#define DRV_NAME "intel_cht_usb_mux" + +struct intel_cht_usb_mux { + struct mutex cfg0_lock; + void __iomem *base; + struct extcon_dev *vbus_extcon; + struct notifier_block vbus_nb; + struct work_struct vbus_work; +}; + +struct intel_cht_extcon_info { + const char *hid; + int hrv; + const char *extcon; +}; + +struct intel_cht_extcon_info vbus_providers[] = { + { "INT33F4", -1, "axp288_extcon" }, + { "INT34D3", 3, "cht_wcove_pwrsrc" }, +}; + +static const unsigned int vbus_cable_ids[] = { + EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP, + EXTCON_CHG_USB_ACA, EXTCON_CHG_USB_FAST, +}; + +static void intel_cht_usb_mux_set_sw_mode(struct intel_cht_usb_mux *mux) +{ + u32 data; +
[PATCH 03/11] mux: consumer.h: Add MUX_USB_* state constant defines
Add MUX_USB_* state constant defines, which can be used by USB device/host and Type-C polarity/role/altmode mux drivers and consumers to ensure that they agree on the meaning of the mux_control_select() state argument. Signed-off-by: Hans de Goede --- include/linux/mux/consumer.h | 16 1 file changed, 16 insertions(+) diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h index 912dd48a3a5d..e3ec9b4db962 100644 --- a/include/linux/mux/consumer.h +++ b/include/linux/mux/consumer.h @@ -15,6 +15,22 @@ #include +/* + * Mux state values for USB muxes, used for both USB device/host role muxes + * as well as for Type-C polarity/role/altmode muxes. + * + * MUX_USB_POLARITY_INV may be or-ed together with any other mux-state as + * inverted-polarity (Type-C plugged in upside down) can happen with any + * other mux-state. + */ +#define MUX_USB_POLARITY_INV BIT(0) /* Polarity inverted bit */ +#define MUX_USB_NONE (1 << 1) /* Mux open / not connected */ +#define MUX_USB_DEVICE (2 << 1) /* USB device mode */ +#define MUX_USB_HOST (3 << 1) /* USB host mode */ +#define MUX_USB_HOST_AND_DP_SRC(4 << 1) /* USB host + 2 lanes Display Port */ +#define MUX_USB_DP_SRC (5 << 1) /* 4 lanes Display Port source */ +#define MUX_USB_STATES (6 << 1) + struct device; struct mux_control; -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/11] mux: core: Add support for getting a mux controller on a non DT platform
On non DT platforms we cannot get the mux_chip by pnode. Other subsystems (regulator, clock, pwm) have the same problem and solve this by allowing platform / board-setup code to add entries to a lookup table and then use this table to look things up. This commit adds support for getting a mux controller on a non DT platform following this pattern. It is based on a simplified version of the pwm subsys lookup code, the dev_id and mux_name parts of a lookup table entry are mandatory in the mux-core implementation. Signed-off-by: Hans de Goede --- drivers/mux/core.c | 96 +++- include/linux/mux/consumer.h | 11 + 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/drivers/mux/core.c b/drivers/mux/core.c index 6142493c327b..8864cc745506 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -24,6 +24,9 @@ #include #include +static DEFINE_MUTEX(mux_lookup_lock); +static LIST_HEAD(mux_lookup_list); + /* * The idle-as-is "state" is not an actual state that may be selected, it * only implies that the state should not be changed. So, use that state @@ -408,6 +411,23 @@ int mux_control_deselect(struct mux_control *mux) } EXPORT_SYMBOL_GPL(mux_control_deselect); +static int parent_name_match(struct device *dev, const void *data) +{ + const char *parent_name = dev_name(dev->parent); + const char *name = data; + + return strcmp(parent_name, name) == 0; +} + +static struct mux_chip *mux_chip_get_by_name(const char *name) +{ + struct device *dev; + + dev = class_find_device(&mux_class, NULL, name, parent_name_match); + + return dev ? to_mux_chip(dev) : NULL; +} + static int of_dev_node_match(struct device *dev, const void *data) { return dev->of_node == data; @@ -479,6 +499,42 @@ static struct mux_control *of_mux_control_get(struct device *dev, } /** + * mux_add_table() - register PWM device consumers + * @table: array of consumers to register + * @num: number of consumers in table + */ +void mux_add_table(struct mux_lookup *table, size_t num) +{ + mutex_lock(&mux_lookup_lock); + + while (num--) { + list_add_tail(&table->list, &mux_lookup_list); + table++; + } + + mutex_unlock(&mux_lookup_lock); +} +EXPORT_SYMBOL_GPL(mux_add_table); + +/** + * mux_remove_table() - unregister PWM device consumers + * @table: array of consumers to unregister + * @num: number of consumers in table + */ +void mux_remove_table(struct mux_lookup *table, size_t num) +{ + mutex_lock(&mux_lookup_lock); + + while (num--) { + list_del(&table->list); + table++; + } + + mutex_unlock(&mux_lookup_lock); +} +EXPORT_SYMBOL_GPL(mux_remove_table); + +/** * mux_control_get() - Get the mux-control for a device. * @dev: The device that needs a mux-control. * @mux_name: The name identifying the mux-control. @@ -487,11 +543,49 @@ static struct mux_control *of_mux_control_get(struct device *dev, */ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) { + struct mux_lookup *m, *chosen = NULL; + const char *dev_id = dev_name(dev); + struct mux_chip *mux_chip; + /* look up via DT first */ if (IS_ENABLED(CONFIG_OF) && dev->of_node) return of_mux_control_get(dev, mux_name); - return ERR_PTR(-ENODEV); + /* +* For non DT we look up the provider in the static table typically +* provided by board setup code. +* +* If a match is found, the provider mux chip is looked up by name +* and a mux-control is requested using the table provided index. +*/ + mutex_lock(&mux_lookup_lock); + list_for_each_entry(m, &mux_lookup_list, list) { + if (WARN_ON(!m->dev_id || !m->mux_name || !m->provider)) + continue; + + if (strcmp(m->dev_id, dev_id) == 0 && + strcmp(m->mux_name, mux_name) == 0) { + chosen = m; + break; + } + } + mutex_unlock(&mux_lookup_lock); + + if (!chosen) + return ERR_PTR(-ENODEV); + + mux_chip = mux_chip_get_by_name(chosen->provider); + if (!mux_chip) + return ERR_PTR(-EPROBE_DEFER); + + if (chosen->index >= mux_chip->controllers) { + dev_err(dev, "Mux lookup table index out of bounds %u >= %u\n", + chosen->index, mux_chip->controllers); + put_device(&mux_chip->dev); + return ERR_PTR(-EINVAL); + } + + return &mux_chip->mux[chosen->index]; } EXPORT_SYMBOL_GPL(mux_control_get); diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h index ea96d4c82be7..912dd48a3a5d 100644 --- a/include/linux/mux/consumer.h +++ b/include/linux/mux/consumer.h @@ -18,6 +18,17 @@ struct device; struct mux_contr
[PATCH 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems
Hi All, This series consists of 4 parts: 1) Core mux changes to add support for getting mux-controllers on non DT platforms and to add some standardised state values for USB 2) Add Intel CHT USB mux and Pericom-PI3USB30532 Type-C mux drivers 3) Hookup the Intel CHT USB mux driver for CHT devices without Type-C 4) Hookup both the Intel CHT USB mux and Pericom-PI3USB30532 Type-C mux drivers to the fusb302 Type-C port controller found on some CHT x86 devs Please review, or in the case of the drivers/mux changes (which are a dep for some of the other patches) merge if the patches are ready. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/11] mux: core: Add of_mux_control_get helper function
Currently the mux_control_get implementation only deals with getting mux controllers on DT platforms. This commit renames the current implementation to of_mux_control_get to reflect this and makes mux_control_get a wrapper around of_mux_control_get. This is a preparation patch for adding support for getting muxes on non DT platforms. Signed-off-by: Hans de Goede --- drivers/mux/core.c | 26 ++ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/mux/core.c b/drivers/mux/core.c index e75d5adc5949..6142493c327b 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -422,14 +422,8 @@ static struct mux_chip *of_get_mux_chip_by_node(struct device_node *np) return dev ? to_mux_chip(dev) : NULL; } -/** - * mux_control_get() - Get the mux-control for a device. - * @dev: The device that needs a mux-control. - * @mux_name: The name identifying the mux-control. - * - * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. - */ -struct mux_control *mux_control_get(struct device *dev, const char *mux_name) +static struct mux_control *of_mux_control_get(struct device *dev, + const char *mux_name) { struct device_node *np = dev->of_node; struct of_phandle_args args; @@ -483,6 +477,22 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) return &mux_chip->mux[controller]; } + +/** + * mux_control_get() - Get the mux-control for a device. + * @dev: The device that needs a mux-control. + * @mux_name: The name identifying the mux-control. + * + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno. + */ +struct mux_control *mux_control_get(struct device *dev, const char *mux_name) +{ + /* look up via DT first */ + if (IS_ENABLED(CONFIG_OF) && dev->of_node) + return of_mux_control_get(dev, mux_name); + + return ERR_PTR(-ENODEV); +} EXPORT_SYMBOL_GPL(mux_control_get); /** -- 2.13.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html