Message ID | 1606140096-1382-6-git-send-email-jun.li@nxp.com |
---|---|
State | New |
Headers | show |
Series | [v6,1/6] dt-bindings: usb: add documentation for typec switch simple driver | expand |
On Mon, Nov 23, 2020 at 10:01:36PM +0800, Li Jun wrote: > This patch adds a simple typec switch driver for cases which only > needs some simple operations but a dedicated driver is required, > current driver only supports GPIO toggle to switch the super speed > active channel according to typec orientation. > > Signed-off-by: Li Jun <jun.li@nxp.com> Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> > --- > Changes for v6: > - Use general mux control for typec switch, currently only support > max 2 GPIOs to control one typec switch with 3 states: orientation > normal(cc1), reverse(cc2), none(deselected both channels). > > Changes for v5: > - A few changes address Andy's comment, remove gpio check as it's > optional, add module name for Kconfig, use correct header files, > and other minor changes. > - Remove the mutex lock as it's not required currently. > > Changes for v4: > - Change driver name to be switch simple from switch GPIO, to make it > generic for possible extention. > - Use compatiable "typec-orientation-switch" instead of bool property > for switch matching. > - Make acitve channel selection GPIO to be optional. > - Remove Andy's R-b tag since the driver changes a lot. > > Change for v3: > - Remove file name in driver description. > - Add Andy Shevchenko's Reviewed-by tag. > > Changes for v2: > - Use the correct head files for gpio api and of_device_id: > #include <linux/gpio/consumer.h> > #include <linux/mod_devicetable.h> > - Add driver dependency on GPIOLIB > > drivers/usb/typec/mux/Kconfig | 10 +++ > drivers/usb/typec/mux/Makefile | 1 + > drivers/usb/typec/mux/switch-simple.c | 126 ++++++++++++++++++++++++++++++++++ > 3 files changed, 137 insertions(+) > > diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig > index a4dbd11..11320d7 100644 > --- a/drivers/usb/typec/mux/Kconfig > +++ b/drivers/usb/typec/mux/Kconfig > @@ -18,4 +18,14 @@ config TYPEC_MUX_INTEL_PMC > control the USB role switch and also the multiplexer/demultiplexer > switches used with USB Type-C Alternate Modes. > > +config TYPEC_SWITCH_SIMPLE > + tristate "Type-C orientation switch simple driver" > + depends on GPIOLIB > + help > + Say Y or M if your system need a simple driver for typec switch > + control, like use GPIO to select active channel. > + > + To compile this driver as a module, choose M here: the > + module will be called switch-simple. > + > endmenu > diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile > index 280a6f5..712d0ad 100644 > --- a/drivers/usb/typec/mux/Makefile > +++ b/drivers/usb/typec/mux/Makefile > @@ -2,3 +2,4 @@ > > obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o > obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o > +obj-$(CONFIG_TYPEC_SWITCH_SIMPLE) += switch-simple.o > diff --git a/drivers/usb/typec/mux/switch-simple.c b/drivers/usb/typec/mux/switch-simple.c > new file mode 100644 > index 0000000..4671169 > --- /dev/null > +++ b/drivers/usb/typec/mux/switch-simple.c > @@ -0,0 +1,126 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Type-C switch simple control driver > + * > + * Copyright 2020 NXP > + * Author: Jun Li <jun.li@nxp.com> > + */ > + > +#include <linux/delay.h> > +#include <linux/gpio/consumer.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/mod_devicetable.h> > +#include <linux/mutex.h> > +#include <linux/mux/driver.h> > +#include <linux/platform_device.h> > +#include <linux/usb/typec_mux.h> > + > +struct typec_switch_simple { > + struct typec_switch *sw; > + struct mux_control *mux; > + struct gpio_descs *switch_gpios; > +}; > + > +static int typec_switch_simple_mux_set(struct mux_control *mux, int state) > +{ > + struct typec_switch_simple *typec_ss = mux_chip_priv(mux->chip); > + DECLARE_BITMAP(values, BITS_PER_TYPE(state)); > + > + values[0] = state; > + gpiod_set_array_value_cansleep(typec_ss->switch_gpios->ndescs, > + typec_ss->switch_gpios->desc, > + typec_ss->switch_gpios->info, > + values); > + > + return 0; > +} > + > +static const struct mux_control_ops typec_switch_mux_ops = { > + .set = typec_switch_simple_mux_set, > +}; > + > +static int typec_switch_simple_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct mux_chip *mux_chip; > + struct typec_switch_desc sw_desc; > + struct typec_switch_simple *typec_ss; > + int idle_state; > + int pins; > + int ret; > + > + pins = gpiod_count(dev, "switch"); > + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*typec_ss)); > + if (IS_ERR(mux_chip)) > + return PTR_ERR(mux_chip); > + > + typec_ss = mux_chip_priv(mux_chip); > + mux_chip->ops = &typec_switch_mux_ops; > + > + /* Get the super speed active channel selection GPIO */ > + typec_ss->switch_gpios = devm_gpiod_get_array_optional(dev, > + "switch", GPIOD_OUT_LOW); > + if (IS_ERR(typec_ss->switch_gpios)) > + return PTR_ERR(typec_ss->switch_gpios); > + > + if (pins) { > + WARN_ON(pins != typec_ss->switch_gpios->ndescs || pins > 2); > + mux_chip->mux->states = pins + 1; > + } > + > + ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); > + if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { > + if (idle_state < 0 || idle_state >= mux_chip->mux->states) { > + dev_err(dev, "invalid idle-state %u\n", idle_state); > + return -EINVAL; > + } > + mux_chip->mux->idle_state = idle_state; > + } > + > + ret = devm_mux_chip_register(dev, mux_chip); > + if (ret < 0) > + return ret; > + > + platform_set_drvdata(pdev, typec_ss); > + sw_desc.drvdata = typec_ss; > + sw_desc.fwnode = dev->fwnode; > + > + typec_ss->sw = typec_switch_register(&mux_chip->dev, &sw_desc); > + if (IS_ERR(typec_ss->sw)) { > + dev_err(dev, "Error registering typec switch: %ld\n", > + PTR_ERR(typec_ss->sw)); > + return PTR_ERR(typec_ss->sw); > + } > + > + return 0; > +} > + > +static int typec_switch_simple_remove(struct platform_device *pdev) > +{ > + struct typec_switch_simple *typec_ss = platform_get_drvdata(pdev); > + > + typec_switch_unregister(typec_ss->sw); > + > + return 0; > +} > + > +static const struct of_device_id of_typec_switch_simple_match[] = { > + { .compatible = "typec-orientation-switch" }, > + { /* Sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, of_typec_switch_simple_match); > + > +static struct platform_driver typec_switch_simple_driver = { > + .probe = typec_switch_simple_probe, > + .remove = typec_switch_simple_remove, > + .driver = { > + .name = "typec-switch-simple", > + .of_match_table = of_typec_switch_simple_match, > + }, > +}; > + > +module_platform_driver(typec_switch_simple_driver); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("TypeC Orientation Switch Simple driver"); > +MODULE_AUTHOR("Jun Li <jun.li@nxp.com>"); > -- > 2.7.4 thanks,
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index a4dbd11..11320d7 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -18,4 +18,14 @@ config TYPEC_MUX_INTEL_PMC control the USB role switch and also the multiplexer/demultiplexer switches used with USB Type-C Alternate Modes. +config TYPEC_SWITCH_SIMPLE + tristate "Type-C orientation switch simple driver" + depends on GPIOLIB + help + Say Y or M if your system need a simple driver for typec switch + control, like use GPIO to select active channel. + + To compile this driver as a module, choose M here: the + module will be called switch-simple. + endmenu diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile index 280a6f5..712d0ad 100644 --- a/drivers/usb/typec/mux/Makefile +++ b/drivers/usb/typec/mux/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o +obj-$(CONFIG_TYPEC_SWITCH_SIMPLE) += switch-simple.o diff --git a/drivers/usb/typec/mux/switch-simple.c b/drivers/usb/typec/mux/switch-simple.c new file mode 100644 index 0000000..4671169 --- /dev/null +++ b/drivers/usb/typec/mux/switch-simple.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Type-C switch simple control driver + * + * Copyright 2020 NXP + * Author: Jun Li <jun.li@nxp.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/mux/driver.h> +#include <linux/platform_device.h> +#include <linux/usb/typec_mux.h> + +struct typec_switch_simple { + struct typec_switch *sw; + struct mux_control *mux; + struct gpio_descs *switch_gpios; +}; + +static int typec_switch_simple_mux_set(struct mux_control *mux, int state) +{ + struct typec_switch_simple *typec_ss = mux_chip_priv(mux->chip); + DECLARE_BITMAP(values, BITS_PER_TYPE(state)); + + values[0] = state; + gpiod_set_array_value_cansleep(typec_ss->switch_gpios->ndescs, + typec_ss->switch_gpios->desc, + typec_ss->switch_gpios->info, + values); + + return 0; +} + +static const struct mux_control_ops typec_switch_mux_ops = { + .set = typec_switch_simple_mux_set, +}; + +static int typec_switch_simple_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mux_chip *mux_chip; + struct typec_switch_desc sw_desc; + struct typec_switch_simple *typec_ss; + int idle_state; + int pins; + int ret; + + pins = gpiod_count(dev, "switch"); + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*typec_ss)); + if (IS_ERR(mux_chip)) + return PTR_ERR(mux_chip); + + typec_ss = mux_chip_priv(mux_chip); + mux_chip->ops = &typec_switch_mux_ops; + + /* Get the super speed active channel selection GPIO */ + typec_ss->switch_gpios = devm_gpiod_get_array_optional(dev, + "switch", GPIOD_OUT_LOW); + if (IS_ERR(typec_ss->switch_gpios)) + return PTR_ERR(typec_ss->switch_gpios); + + if (pins) { + WARN_ON(pins != typec_ss->switch_gpios->ndescs || pins > 2); + mux_chip->mux->states = pins + 1; + } + + ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state); + if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) { + if (idle_state < 0 || idle_state >= mux_chip->mux->states) { + dev_err(dev, "invalid idle-state %u\n", idle_state); + return -EINVAL; + } + mux_chip->mux->idle_state = idle_state; + } + + ret = devm_mux_chip_register(dev, mux_chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, typec_ss); + sw_desc.drvdata = typec_ss; + sw_desc.fwnode = dev->fwnode; + + typec_ss->sw = typec_switch_register(&mux_chip->dev, &sw_desc); + if (IS_ERR(typec_ss->sw)) { + dev_err(dev, "Error registering typec switch: %ld\n", + PTR_ERR(typec_ss->sw)); + return PTR_ERR(typec_ss->sw); + } + + return 0; +} + +static int typec_switch_simple_remove(struct platform_device *pdev) +{ + struct typec_switch_simple *typec_ss = platform_get_drvdata(pdev); + + typec_switch_unregister(typec_ss->sw); + + return 0; +} + +static const struct of_device_id of_typec_switch_simple_match[] = { + { .compatible = "typec-orientation-switch" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_typec_switch_simple_match); + +static struct platform_driver typec_switch_simple_driver = { + .probe = typec_switch_simple_probe, + .remove = typec_switch_simple_remove, + .driver = { + .name = "typec-switch-simple", + .of_match_table = of_typec_switch_simple_match, + }, +}; + +module_platform_driver(typec_switch_simple_driver); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TypeC Orientation Switch Simple driver"); +MODULE_AUTHOR("Jun Li <jun.li@nxp.com>");
This patch adds a simple typec switch driver for cases which only needs some simple operations but a dedicated driver is required, current driver only supports GPIO toggle to switch the super speed active channel according to typec orientation. Signed-off-by: Li Jun <jun.li@nxp.com> --- Changes for v6: - Use general mux control for typec switch, currently only support max 2 GPIOs to control one typec switch with 3 states: orientation normal(cc1), reverse(cc2), none(deselected both channels). Changes for v5: - A few changes address Andy's comment, remove gpio check as it's optional, add module name for Kconfig, use correct header files, and other minor changes. - Remove the mutex lock as it's not required currently. Changes for v4: - Change driver name to be switch simple from switch GPIO, to make it generic for possible extention. - Use compatiable "typec-orientation-switch" instead of bool property for switch matching. - Make acitve channel selection GPIO to be optional. - Remove Andy's R-b tag since the driver changes a lot. Change for v3: - Remove file name in driver description. - Add Andy Shevchenko's Reviewed-by tag. Changes for v2: - Use the correct head files for gpio api and of_device_id: #include <linux/gpio/consumer.h> #include <linux/mod_devicetable.h> - Add driver dependency on GPIOLIB drivers/usb/typec/mux/Kconfig | 10 +++ drivers/usb/typec/mux/Makefile | 1 + drivers/usb/typec/mux/switch-simple.c | 126 ++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+)