The general mux controller can be easily extended to support various mux selection, this especially fits typec orientation switch block with a dedicated driver. Signed-off-by: Li Jun <jun.li@xxxxxxx> --- New patch for v6. drivers/usb/typec/bus.h | 1 + drivers/usb/typec/mux.c | 44 ++++++++++++++++++++++++++++++++++++++++--- include/linux/usb/typec_mux.h | 7 +------ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h index 8ba8112..235ee82 100644 --- a/drivers/usb/typec/bus.h +++ b/drivers/usb/typec/bus.h @@ -38,6 +38,7 @@ extern struct class typec_mux_class; struct typec_switch { struct device dev; typec_switch_set_fn_t set; + struct mux_control *mux_ctrl; }; struct typec_mux { diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index 0219aa4..afc4537 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -14,6 +14,7 @@ #include <linux/property.h> #include <linux/slab.h> #include <linux/usb/typec_mux.h> +#include <linux/mux/consumer.h> #include "bus.h" @@ -42,10 +43,8 @@ static void *typec_switch_match(struct device_connection *con, int ep, if (con->id && !fwnode_is_compatible(con->fwnode, con->id) && !fwnode_property_present(con->fwnode, con->id)) return NULL; - dev = class_find_device(&typec_mux_class, NULL, con->fwnode, switch_fwnode_match); - return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER); } @@ -71,6 +70,19 @@ struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_typec_switch_get); +struct typec_switch *typec_switch_get(struct device *dev) +{ + struct mux_control *typec_mc = mux_control_get(dev->parent, + "mux-typec-switch"); + struct typec_switch *sw = fwnode_typec_switch_get(dev_fwnode(dev)); + + if (!IS_ERR_OR_NULL(sw) && !IS_ERR_OR_NULL(typec_mc)) + sw->mux_ctrl = typec_mc; + + return sw; +} +EXPORT_SYMBOL_GPL(typec_switch_get); + /** * typec_put_switch - Release USB Type-C orientation switch * @sw: USB Type-C orientation switch @@ -142,13 +154,39 @@ typec_switch_register(struct device *parent, } EXPORT_SYMBOL_GPL(typec_switch_register); +static int typec_switch_mux_ctrl(struct mux_control *sw_mux, + enum typec_orientation orientation) +{ + int ret = 0; + + if (!sw_mux) + return -EINVAL; + + switch (orientation) { + case TYPEC_ORIENTATION_NORMAL: + ret = mux_control_select(sw_mux, 1); + break; + case TYPEC_ORIENTATION_REVERSE: + ret = mux_control_select(sw_mux, 0); + break; + case TYPEC_ORIENTATION_NONE: + ret = mux_control_deselect(sw_mux); + break; + } + + return ret; +} + int typec_switch_set(struct typec_switch *sw, enum typec_orientation orientation) { if (IS_ERR_OR_NULL(sw)) return 0; - return sw->set(sw, orientation); + if (sw->mux_ctrl) + return typec_switch_mux_ctrl(sw->mux_ctrl, orientation); + else + return sw->set(sw, orientation); } EXPORT_SYMBOL_GPL(typec_switch_set); diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h index a9d9957..e2ea141 100644 --- a/include/linux/usb/typec_mux.h +++ b/include/linux/usb/typec_mux.h @@ -26,15 +26,10 @@ struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode); void typec_switch_put(struct typec_switch *sw); int typec_switch_set(struct typec_switch *sw, enum typec_orientation orientation); - -static inline struct typec_switch *typec_switch_get(struct device *dev) -{ - return fwnode_typec_switch_get(dev_fwnode(dev)); -} - struct typec_switch * typec_switch_register(struct device *parent, const struct typec_switch_desc *desc); +struct typec_switch *typec_switch_get(struct device *dev); void typec_switch_unregister(struct typec_switch *sw); void typec_switch_set_drvdata(struct typec_switch *sw, void *data); -- 2.7.4