From: Hans de Goede <hdegoede@redhat.com>
To: Peter Rosin <peda@lysator.liu.se>,
MyungJoo Ham <myungjoo.ham@samsung.com>,
Chanwoo Choi <cw00.choi@samsung.com>,
Guenter Roeck <linux@roeck-us.net>,
Heikki Krogerus <heikki.krogerus@linux.intel.com>,
Darren Hart <dvhart@infradead.org>,
Andy Shevchenko <andy@infradead.org>,
Mathias Nyman <mathias.nyman@intel.com>
Cc: devel@driverdev.osuosl.org,
Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
platform-driver-x86@vger.kernel.org,
Sathyanarayanan Kuppuswamy Natarajan <sathyaosid@gmail.com>
Subject: Re: [PATCH 05/11] mux: Add Intel Cherrytrail USB mux driver
Date: Tue, 5 Sep 2017 13:09:14 +0200 [thread overview]
Message-ID: <ccec86a2-5792-7d11-70ef-243bc2c2cf8c@redhat.com> (raw)
In-Reply-To: <d0178656-2274-b718-4187-8b5b0fbecb4a@lysator.liu.se>
Hi,
On 04-09-17 13:19, Peter Rosin wrote:
> Hi!
>
> Some comments inline...
>
> On 2017-09-01 23:48, Hans de Goede wrote:
>> 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 <hdegoede@redhat.com>
>> ---
>> 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
>
> I dislike underscores in file names (and other names), please use
> dashes where possible. Also, please keep the list sorted.
>
>>
>> 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
>
> Dito.
Ok, will fix both for v2.
>> diff --git a/drivers/mux/intel_cht_usb_mux.c b/drivers/mux/intel_cht_usb_mux.c
>> new file mode 100644
>> index 000000000000..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 <hdegoede@redhat.com>
>> + *
>> + * 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 <linux/acpi.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/extcon.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/mux/consumer.h> /* For the MUX_USB_* defines */
>> +#include <linux/mux/driver.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/workqueue.h>
>> +
>> +/* 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_TIMEOUT 1000
>> +
>> +#define DRV_NAME "intel_cht_usb_mux"
>
> Dashes, please, if possible. Or are there perhaps a lot of precedent
> for other cherrytrail driver names? Because consistency across
> the tree is a tad more important than my issues with underscores...
The Cherry Trail code uses _ for device-names everywhere, so lets
keep this one as is.
>
>> +
>> +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" },
>> +};
>
> Ditto.
I assume you mean the _ thingie with ditto? These are
names coded in existing drivers, so sorry this cannot
be (easily) changed.
> And static const. What about:
>
> static const struct intel_cht_extcon_info vbus_providers[] = {
> { .hid = "INT33F4", .hrv = -1, .extcon = "axp288_extcon", },
> { .hid = "INT34D3", .hrv = 3, .extcon = "cht_wcove_pwrsrc", },
> };
Sure, WFM.
>> +
>> +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;
>> +
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + if (!(data & SW_IDPIN_EN)) {
>> + data |= SW_IDPIN_EN;
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> + }
>> +}
>
> Is SW_IDPIN_EN a bit that unlocks the other bits in the register for
> writing? Once? Perhaps it interacts with the mode switch confirmation
> loop? Anyway, I'd like to see a comment about why this bit needs to be
> set so many times.
It is not an unlock bit as much as it is an enable SW control bit,
I think Intel sourced the USB PHY and mux design from some 3th party,
because there is no dedicated hardware ID pin (instead a GPIO is used)
and we need to propagate the value of the GPIO connected to the ID
pin of the OTG connector to the SW_IDPIN register bit.
And for the PHY/mux to listen to the SW_IDPIN bit rather then to
the (Not Connected) physical ID pin we need to set SW_IDPIN_EN.
But thinking about this more, also given Andy's comments I'm
pretty sure I can safely just or this bit in while doing the
read-modify-write to set the SW_IDPIN or SW_VBUS_VALID bit
itself, so this can be removed.
>
>> +
>> +static int intel_cht_usb_mux_set_mux(struct mux_control *mux_ctrl, int state)
>> +{
>> + struct intel_cht_usb_mux *mux = mux_chip_priv(mux_ctrl->chip);
>
> The "mux" variable name is used for the mux_control in other drivers, and
> the private data is named something else. Please fix this all over the
> driver for consistency across the subsys.
Ok.
>
>> + unsigned long timeout;
>> + bool host_mode;
>> + u32 data;
>> +
>> + mutex_lock(&mux->cfg0_lock);
>> +
>> + intel_cht_usb_mux_set_sw_mode(mux);
>> +
>> + /* Set idpin value as requested */
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + switch (state & ~MUX_USB_POLARITY_INV) {
>> + case MUX_USB_NONE:
>> + case MUX_USB_DEVICE:
>> + data |= SW_IDPIN;
>> + host_mode = false;
>> + break;
>> + default:
>> + data &= ~SW_IDPIN;
>> + host_mode = true;
>> + }
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> +
>> + mutex_unlock(&mux->cfg0_lock);
>> +
>> + /* In most case it takes about 600ms to finish mode switching */
>> + timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
>> +
>> + /* Polling on CFG1 register to confirm mode switch.*/
>> + while (1) {
>> + data = readl(mux->base + DUAL_ROLE_CFG1);
>> + if (!!(data & HOST_MODE) == host_mode)
>> + break;
>> +
>> + /* Interval for polling is set to about 5 - 10 ms */
>> + usleep_range(5000, 10000);
>> +
>> + if (time_after(jiffies, timeout)) {
>> + dev_warn(&mux_ctrl->chip->dev,
>> + "Timeout waiting for mux to switch\n");
>> + break;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void intel_cht_usb_mux_set_vbus_valid(struct intel_cht_usb_mux *mux,
>> + bool valid)
>> +{
>> + u32 data;
>> +
>> + mutex_lock(&mux->cfg0_lock);
>> +
>> + intel_cht_usb_mux_set_sw_mode(mux);
>> +
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + if (valid)
>> + data |= SW_VBUS_VALID;
>> + else
>> + data &= ~SW_VBUS_VALID;
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> +
>> + mutex_unlock(&mux->cfg0_lock);
>> +}
>> +
>> +static void intel_cht_usb_mux_vbus_work(struct work_struct *work)
>> +{
>> + struct intel_cht_usb_mux *mux =
>> + container_of(work, struct intel_cht_usb_mux, vbus_work);
>> + bool vbus_present = false;
>> + int i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(vbus_cable_ids); i++) {
>> + if (extcon_get_state(mux->vbus_extcon, vbus_cable_ids[i]) > 0) {
>> + vbus_present = true;
>> + break;
>> + }
>> + }
>> +
>> + intel_cht_usb_mux_set_vbus_valid(mux, vbus_present);
>> +}
>> +
>> +static int intel_cht_usb_mux_vbus_extcon_evt(struct notifier_block *nb,
>> + unsigned long event, void *param)
>> +{
>> + struct intel_cht_usb_mux *mux =
>> + container_of(nb, struct intel_cht_usb_mux, vbus_nb);
>> +
>> + schedule_work(&mux->vbus_work);
>> +
>> + return NOTIFY_OK;
>> +}
>> +
>> +static const struct mux_control_ops intel_cht_usb_mux_ops = {
>> + .set = intel_cht_usb_mux_set_mux,
>> +};
>> +
>> +static int intel_cht_usb_mux_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct intel_cht_usb_mux *mux;
>> + struct mux_chip *mux_chip;
>> + struct resource *res;
>> + resource_size_t size;
>> + int i, ret;
>> +
>> + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux));
>> + if (IS_ERR(mux_chip))
>> + return PTR_ERR(mux_chip);
>> +
>> + mux_chip->ops = &intel_cht_usb_mux_ops;
>> + mux_chip->mux[0].states = MUX_USB_STATES;
>
> This is "a lie" I think, the mux only supports two states; device and host.
Right, this is the result me choosing to use a single set of defines
for both the USB-role and Type-C mode switches and then calling both
muxes with the same value. Will fix for v2.
Regards,
Hans
> Looks good otherwise, if you also consider the remarks from Andy.
>
> Cheers,
> Peter
>
>> + mux = mux_chip_priv(mux_chip);
>> + mutex_init(&mux->cfg0_lock);
>> +
>> + /*
>> + * Besides controlling the mux we also need to control the vbus_valid
>> + * flag for device/gadget mode to work properly. To do this we monitor
>> + * the extcon interface exported by the PMIC drivers for the PMICs used
>> + * with the Cherry Trail SoC.
>> + *
>> + * We try to get the extcon_dev before registering the mux as this
>> + * may lead to us exiting with -EPROBE_DEFER.
>> + */
>> + for (i = 0 ; i < ARRAY_SIZE(vbus_providers); i++) {
>> + if (!acpi_dev_present(vbus_providers[i].hid, NULL,
>> + vbus_providers[i].hrv))
>> + continue;
>> +
>> + mux->vbus_extcon = extcon_get_extcon_dev(
>> + vbus_providers[i].extcon);
>> + if (mux->vbus_extcon == NULL)
>> + return -EPROBE_DEFER;
>> +
>> + dev_info(dev, "using extcon '%s' for vbus-valid\n",
>> + vbus_providers[i].extcon);
>> + break;
>> + }
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + size = (res->end + 1) - res->start;
>> + mux->base = devm_ioremap_nocache(dev, res->start, size);
>> + if (IS_ERR(mux->base)) {
>> + ret = PTR_ERR(mux->base);
>> + dev_err(dev, "can't iomap registers: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = devm_mux_chip_register(dev, mux_chip);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (mux->vbus_extcon) {
>> + INIT_WORK(&mux->vbus_work, intel_cht_usb_mux_vbus_work);
>> + mux->vbus_nb.notifier_call = intel_cht_usb_mux_vbus_extcon_evt;
>> + ret = devm_extcon_register_notifier_all(dev, mux->vbus_extcon,
>> + &mux->vbus_nb);
>> + if (ret) {
>> + dev_err(dev, "can't register vbus extcon notifier: %d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + /* Sync initial mode */
>> + schedule_work(&mux->vbus_work);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct platform_device_id intel_cht_usb_mux_table[] = {
>> + { .name = DRV_NAME },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(platform, intel_cht_usb_mux_table);
>> +
>> +static struct platform_driver intel_cht_usb_mux_driver = {
>> + .driver = {
>> + .name = DRV_NAME,
>> + },
>> + .id_table = intel_cht_usb_mux_table,
>> + .probe = intel_cht_usb_mux_probe,
>> +};
>> +
>> +module_platform_driver(intel_cht_usb_mux_driver);
>> +
>> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
>> +MODULE_DESCRIPTION("Intel Cherrytrail USB mux driver");
>> +MODULE_LICENSE("GPL");
>>
>
WARNING: multiple messages have this Message-ID (diff)
From: Hans de Goede <hdegoede@redhat.com>
To: Peter Rosin <peda@lysator.liu.se>,
MyungJoo Ham <myungjoo.ham@samsung.com>,
Chanwoo Choi <cw00.choi@samsung.com>,
Guenter Roeck <linux@roeck-us.net>,
Heikki Krogerus <heikki.krogerus@linux.intel.com>,
Darren Hart <dvhart@infradead.org>,
Andy Shevchenko <andy@infradead.org>,
Mathias Nyman <mathias.nyman@intel.com>
Cc: platform-driver-x86@vger.kernel.org, devel@driverdev.osuosl.org,
Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com>,
Sathyanarayanan Kuppuswamy Natarajan <sathyaosid@gmail.com>,
linux-kernel@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-usb@vger.kernel.org
Subject: Re: [PATCH 05/11] mux: Add Intel Cherrytrail USB mux driver
Date: Tue, 5 Sep 2017 13:09:14 +0200 [thread overview]
Message-ID: <ccec86a2-5792-7d11-70ef-243bc2c2cf8c@redhat.com> (raw)
In-Reply-To: <d0178656-2274-b718-4187-8b5b0fbecb4a@lysator.liu.se>
Hi,
On 04-09-17 13:19, Peter Rosin wrote:
> Hi!
>
> Some comments inline...
>
> On 2017-09-01 23:48, Hans de Goede wrote:
>> 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 <hdegoede@redhat.com>
>> ---
>> 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
>
> I dislike underscores in file names (and other names), please use
> dashes where possible. Also, please keep the list sorted.
>
>>
>> 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
>
> Dito.
Ok, will fix both for v2.
>> diff --git a/drivers/mux/intel_cht_usb_mux.c b/drivers/mux/intel_cht_usb_mux.c
>> new file mode 100644
>> index 000000000000..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 <hdegoede@redhat.com>
>> + *
>> + * 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 <linux/acpi.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/extcon.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/mux/consumer.h> /* For the MUX_USB_* defines */
>> +#include <linux/mux/driver.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/workqueue.h>
>> +
>> +/* 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_TIMEOUT 1000
>> +
>> +#define DRV_NAME "intel_cht_usb_mux"
>
> Dashes, please, if possible. Or are there perhaps a lot of precedent
> for other cherrytrail driver names? Because consistency across
> the tree is a tad more important than my issues with underscores...
The Cherry Trail code uses _ for device-names everywhere, so lets
keep this one as is.
>
>> +
>> +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" },
>> +};
>
> Ditto.
I assume you mean the _ thingie with ditto? These are
names coded in existing drivers, so sorry this cannot
be (easily) changed.
> And static const. What about:
>
> static const struct intel_cht_extcon_info vbus_providers[] = {
> { .hid = "INT33F4", .hrv = -1, .extcon = "axp288_extcon", },
> { .hid = "INT34D3", .hrv = 3, .extcon = "cht_wcove_pwrsrc", },
> };
Sure, WFM.
>> +
>> +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;
>> +
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + if (!(data & SW_IDPIN_EN)) {
>> + data |= SW_IDPIN_EN;
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> + }
>> +}
>
> Is SW_IDPIN_EN a bit that unlocks the other bits in the register for
> writing? Once? Perhaps it interacts with the mode switch confirmation
> loop? Anyway, I'd like to see a comment about why this bit needs to be
> set so many times.
It is not an unlock bit as much as it is an enable SW control bit,
I think Intel sourced the USB PHY and mux design from some 3th party,
because there is no dedicated hardware ID pin (instead a GPIO is used)
and we need to propagate the value of the GPIO connected to the ID
pin of the OTG connector to the SW_IDPIN register bit.
And for the PHY/mux to listen to the SW_IDPIN bit rather then to
the (Not Connected) physical ID pin we need to set SW_IDPIN_EN.
But thinking about this more, also given Andy's comments I'm
pretty sure I can safely just or this bit in while doing the
read-modify-write to set the SW_IDPIN or SW_VBUS_VALID bit
itself, so this can be removed.
>
>> +
>> +static int intel_cht_usb_mux_set_mux(struct mux_control *mux_ctrl, int state)
>> +{
>> + struct intel_cht_usb_mux *mux = mux_chip_priv(mux_ctrl->chip);
>
> The "mux" variable name is used for the mux_control in other drivers, and
> the private data is named something else. Please fix this all over the
> driver for consistency across the subsys.
Ok.
>
>> + unsigned long timeout;
>> + bool host_mode;
>> + u32 data;
>> +
>> + mutex_lock(&mux->cfg0_lock);
>> +
>> + intel_cht_usb_mux_set_sw_mode(mux);
>> +
>> + /* Set idpin value as requested */
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + switch (state & ~MUX_USB_POLARITY_INV) {
>> + case MUX_USB_NONE:
>> + case MUX_USB_DEVICE:
>> + data |= SW_IDPIN;
>> + host_mode = false;
>> + break;
>> + default:
>> + data &= ~SW_IDPIN;
>> + host_mode = true;
>> + }
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> +
>> + mutex_unlock(&mux->cfg0_lock);
>> +
>> + /* In most case it takes about 600ms to finish mode switching */
>> + timeout = jiffies + msecs_to_jiffies(DUAL_ROLE_CFG1_POLL_TIMEOUT);
>> +
>> + /* Polling on CFG1 register to confirm mode switch.*/
>> + while (1) {
>> + data = readl(mux->base + DUAL_ROLE_CFG1);
>> + if (!!(data & HOST_MODE) == host_mode)
>> + break;
>> +
>> + /* Interval for polling is set to about 5 - 10 ms */
>> + usleep_range(5000, 10000);
>> +
>> + if (time_after(jiffies, timeout)) {
>> + dev_warn(&mux_ctrl->chip->dev,
>> + "Timeout waiting for mux to switch\n");
>> + break;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void intel_cht_usb_mux_set_vbus_valid(struct intel_cht_usb_mux *mux,
>> + bool valid)
>> +{
>> + u32 data;
>> +
>> + mutex_lock(&mux->cfg0_lock);
>> +
>> + intel_cht_usb_mux_set_sw_mode(mux);
>> +
>> + data = readl(mux->base + DUAL_ROLE_CFG0);
>> + if (valid)
>> + data |= SW_VBUS_VALID;
>> + else
>> + data &= ~SW_VBUS_VALID;
>> + writel(data, mux->base + DUAL_ROLE_CFG0);
>> +
>> + mutex_unlock(&mux->cfg0_lock);
>> +}
>> +
>> +static void intel_cht_usb_mux_vbus_work(struct work_struct *work)
>> +{
>> + struct intel_cht_usb_mux *mux =
>> + container_of(work, struct intel_cht_usb_mux, vbus_work);
>> + bool vbus_present = false;
>> + int i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(vbus_cable_ids); i++) {
>> + if (extcon_get_state(mux->vbus_extcon, vbus_cable_ids[i]) > 0) {
>> + vbus_present = true;
>> + break;
>> + }
>> + }
>> +
>> + intel_cht_usb_mux_set_vbus_valid(mux, vbus_present);
>> +}
>> +
>> +static int intel_cht_usb_mux_vbus_extcon_evt(struct notifier_block *nb,
>> + unsigned long event, void *param)
>> +{
>> + struct intel_cht_usb_mux *mux =
>> + container_of(nb, struct intel_cht_usb_mux, vbus_nb);
>> +
>> + schedule_work(&mux->vbus_work);
>> +
>> + return NOTIFY_OK;
>> +}
>> +
>> +static const struct mux_control_ops intel_cht_usb_mux_ops = {
>> + .set = intel_cht_usb_mux_set_mux,
>> +};
>> +
>> +static int intel_cht_usb_mux_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct intel_cht_usb_mux *mux;
>> + struct mux_chip *mux_chip;
>> + struct resource *res;
>> + resource_size_t size;
>> + int i, ret;
>> +
>> + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux));
>> + if (IS_ERR(mux_chip))
>> + return PTR_ERR(mux_chip);
>> +
>> + mux_chip->ops = &intel_cht_usb_mux_ops;
>> + mux_chip->mux[0].states = MUX_USB_STATES;
>
> This is "a lie" I think, the mux only supports two states; device and host.
Right, this is the result me choosing to use a single set of defines
for both the USB-role and Type-C mode switches and then calling both
muxes with the same value. Will fix for v2.
Regards,
Hans
> Looks good otherwise, if you also consider the remarks from Andy.
>
> Cheers,
> Peter
>
>> + mux = mux_chip_priv(mux_chip);
>> + mutex_init(&mux->cfg0_lock);
>> +
>> + /*
>> + * Besides controlling the mux we also need to control the vbus_valid
>> + * flag for device/gadget mode to work properly. To do this we monitor
>> + * the extcon interface exported by the PMIC drivers for the PMICs used
>> + * with the Cherry Trail SoC.
>> + *
>> + * We try to get the extcon_dev before registering the mux as this
>> + * may lead to us exiting with -EPROBE_DEFER.
>> + */
>> + for (i = 0 ; i < ARRAY_SIZE(vbus_providers); i++) {
>> + if (!acpi_dev_present(vbus_providers[i].hid, NULL,
>> + vbus_providers[i].hrv))
>> + continue;
>> +
>> + mux->vbus_extcon = extcon_get_extcon_dev(
>> + vbus_providers[i].extcon);
>> + if (mux->vbus_extcon == NULL)
>> + return -EPROBE_DEFER;
>> +
>> + dev_info(dev, "using extcon '%s' for vbus-valid\n",
>> + vbus_providers[i].extcon);
>> + break;
>> + }
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + size = (res->end + 1) - res->start;
>> + mux->base = devm_ioremap_nocache(dev, res->start, size);
>> + if (IS_ERR(mux->base)) {
>> + ret = PTR_ERR(mux->base);
>> + dev_err(dev, "can't iomap registers: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = devm_mux_chip_register(dev, mux_chip);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (mux->vbus_extcon) {
>> + INIT_WORK(&mux->vbus_work, intel_cht_usb_mux_vbus_work);
>> + mux->vbus_nb.notifier_call = intel_cht_usb_mux_vbus_extcon_evt;
>> + ret = devm_extcon_register_notifier_all(dev, mux->vbus_extcon,
>> + &mux->vbus_nb);
>> + if (ret) {
>> + dev_err(dev, "can't register vbus extcon notifier: %d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + /* Sync initial mode */
>> + schedule_work(&mux->vbus_work);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct platform_device_id intel_cht_usb_mux_table[] = {
>> + { .name = DRV_NAME },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(platform, intel_cht_usb_mux_table);
>> +
>> +static struct platform_driver intel_cht_usb_mux_driver = {
>> + .driver = {
>> + .name = DRV_NAME,
>> + },
>> + .id_table = intel_cht_usb_mux_table,
>> + .probe = intel_cht_usb_mux_probe,
>> +};
>> +
>> +module_platform_driver(intel_cht_usb_mux_driver);
>> +
>> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
>> +MODULE_DESCRIPTION("Intel Cherrytrail USB mux driver");
>> +MODULE_LICENSE("GPL");
>>
>
next prev parent reply other threads:[~2017-09-05 11:09 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-01 21:48 [PATCH 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems Hans de Goede
2017-09-01 21:48 ` [PATCH 01/11] mux: core: Add of_mux_control_get helper function Hans de Goede
2017-09-01 21:48 ` [PATCH 02/11] mux: core: Add support for getting a mux controller on a non DT platform Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-02 19:13 ` sathya
2017-09-04 14:21 ` Hans de Goede
2017-09-04 11:19 ` Peter Rosin
[not found] ` <0c882d23-d008-3d61-27be-3fa22bf59521-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
2017-09-05 10:58 ` Hans de Goede
2017-09-05 10:58 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 03/11] mux: consumer.h: Add MUX_USB_* state constant defines Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-02 10:10 ` Andy Shevchenko
2017-09-02 11:59 ` Hans de Goede
2017-09-02 14:59 ` Guenter Roeck
2017-09-02 14:59 ` Guenter Roeck
2017-09-02 15:59 ` Hans de Goede
[not found] ` <3e777501-aa94-70ae-3dc5-f64a15fd9704-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-09-02 19:06 ` Guenter Roeck
2017-09-02 19:06 ` Guenter Roeck
2017-09-02 19:46 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 04/11] usb: xhci: Add Intel cherrytrail extended cap / otg phy mux handling Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-04 7:31 ` Heikki Krogerus
2017-09-05 10:06 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 05/11] mux: Add Intel Cherrytrail USB mux driver Hans de Goede
[not found] ` <20170901214845.7153-6-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-09-02 10:19 ` Andy Shevchenko
2017-09-02 10:19 ` Andy Shevchenko
2017-09-02 10:37 ` Dan Carpenter
2017-09-04 14:07 ` Hans de Goede
2017-09-04 11:19 ` Peter Rosin
2017-09-05 11:09 ` Hans de Goede [this message]
2017-09-05 11:09 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 06/11] mux: Add Pericom PI3USB30532 Type-C " Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-04 11:19 ` Peter Rosin
2017-09-05 7:46 ` Peter Rosin
2017-09-01 21:48 ` [PATCH 07/11] extcon: intel-int3496: Add support for controlling the USB-role mux Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-02 10:39 ` Andy Shevchenko
2017-09-02 10:39 ` Andy Shevchenko
2017-09-04 14:11 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 08/11] staging: typec: tcpm: Set mux to device mode when configured as such Hans de Goede
2017-09-01 21:48 ` [PATCH 09/11] staging: typec: Add Generic TCPC mux driver using the mux subsys Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 10/11] staging: typec: fusb302: Hook up mux support using tcpc_gen_mux support Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-01 21:48 ` [PATCH 11/11] platform/x86: intel_cht_int33fe: Add mux mappings for the Type-C port Hans de Goede
2017-09-01 21:48 ` Hans de Goede
2017-09-02 10:42 ` Andy Shevchenko
[not found] ` <CAHp75VdFAY6HaOh5-yBsgBoeJgpDrVUizX+zESq1Pr0-sQR6Pg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2017-09-04 14:20 ` Hans de Goede
2017-09-04 14:20 ` Hans de Goede
2017-09-04 11:18 ` [PATCH 00/11] mux/typec: Add USB / TypeC mux drivers and hook them up on some x86 systems Peter Rosin
2017-09-05 10:54 ` Hans de Goede
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ccec86a2-5792-7d11-70ef-243bc2c2cf8c@redhat.com \
--to=hdegoede@redhat.com \
--cc=andy@infradead.org \
--cc=cw00.choi@samsung.com \
--cc=devel@driverdev.osuosl.org \
--cc=dvhart@infradead.org \
--cc=gregkh@linuxfoundation.org \
--cc=heikki.krogerus@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=mathias.nyman@intel.com \
--cc=myungjoo.ham@samsung.com \
--cc=peda@lysator.liu.se \
--cc=platform-driver-x86@vger.kernel.org \
--cc=sathyanarayanan.kuppuswamy@linux.intel.com \
--cc=sathyaosid@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.