From 1362aa149fe5eb77ddd8ea29ac28b4be13cda883 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Sun, 29 Nov 2020 10:50:20 +0800 Subject: [PATCH] usb: misc: nb7vpq904m: allow USB control connect and disconnect add redriver_notify_connect() and redriver_notify_disconnect(). Change-Id: I48b2198df2a2257b13946fd8fcd7517f51073d45 Signed-off-by: Linyu Yuan --- drivers/usb/misc/ssusb-redriver-nb7vpq904m.c | 110 +++++++++++++++++-- include/linux/usb/redriver.h | 12 ++ 2 files changed, 114 insertions(+), 8 deletions(-) diff --git a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c index 7b6d3d0fc76a..9ca119f5a6bc 100644 --- a/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c +++ b/drivers/usb/misc/ssusb-redriver-nb7vpq904m.c @@ -99,6 +99,7 @@ struct ssusb_redriver { u8 flat_gain[CHAN_MODE_NUM][CHANNEL_NUM]; u8 gen_dev_val; + int ucsi_i2c_write_err; struct dentry *debug_root; }; @@ -132,7 +133,7 @@ static int redriver_i2c_reg_set(struct ssusb_redriver *redriver, return 0; } -static void ssusb_redriver_gen_dev_set(struct ssusb_redriver *redriver) +static int ssusb_redriver_gen_dev_set(struct ssusb_redriver *redriver) { u8 val = 0; @@ -192,7 +193,7 @@ static void ssusb_redriver_gen_dev_set(struct ssusb_redriver *redriver) redriver->gen_dev_val = val; - redriver_i2c_reg_set(redriver, GEN_DEV_SET_REG, val); + return redriver_i2c_reg_set(redriver, GEN_DEV_SET_REG, val); } static int ssusb_redriver_param_config(struct ssusb_redriver *redriver, @@ -352,7 +353,7 @@ static int ssusb_redriver_channel_update(struct ssusb_redriver *redriver) return 0; err: - dev_err(redriver->dev, "channel parameters update failure.\n"); + dev_err(redriver->dev, "channel parameters update failure(%d).\n", ret); return ret; } @@ -458,6 +459,7 @@ static int ssusb_redriver_ucsi_notifier(struct notifier_block *nb, container_of(nb, struct ssusb_redriver, ucsi_nb); struct ucsi_glink_constat_info *info = data; enum operation_mode op_mode; + int ret; if (info->connect && !info->partner_change) return NOTIFY_DONE; @@ -501,25 +503,115 @@ static int ssusb_redriver_ucsi_notifier(struct notifier_block *nb, "CC1" : "CC2"); } - ssusb_redriver_channel_update(redriver); + ret = ssusb_redriver_channel_update(redriver); + if (ret) { + dev_dbg(redriver->dev, "i2c bus may not resume(%d)\n", ret); + redriver->ucsi_i2c_write_err = ret; + return NOTIFY_DONE; + } ssusb_redriver_gen_dev_set(redriver); return NOTIFY_OK; } +int redriver_notify_connect(struct device_node *node) +{ + struct ssusb_redriver *redriver; + struct i2c_client *client; + + if (!node) + return -ENODEV; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -ENODEV; + + redriver = i2c_get_clientdata(client); + if (!redriver) + return -EINVAL; + + /* 1. no operation in recovery mode. + * 2. needed when usb related mode set. + * 3. currently ucsi notification arrive to redriver earlier than usb, + * in ucsi notification callback, save mode even i2c write failed, + * but add ucsi_i2c_write_err to indicate i2c write error, + * this allow usb trigger i2c write again by check it. + * !!! if future remove ucsi, ucsi_i2c_write_err can be removed, + * and this function also need update !!!. + */ + if ((redriver->op_mode == OP_MODE_DEFAULT) || + ((redriver->op_mode != OP_MODE_USB) && + (redriver->op_mode != OP_MODE_USB_AND_DP)) || + (!redriver->ucsi_i2c_write_err)) + return 0; + + dev_dbg(redriver->dev, "op mode %s\n", + OPMODESTR(redriver->op_mode)); + + /* !!! assume i2c resume complete here !!! */ + ssusb_redriver_channel_update(redriver); + ssusb_redriver_gen_dev_set(redriver); + + redriver->ucsi_i2c_write_err = 0; + + return 0; +} +EXPORT_SYMBOL(redriver_notify_connect); + +int redriver_notify_disconnect(struct device_node *node) +{ + struct ssusb_redriver *redriver; + struct i2c_client *client; + + if (!node) + return -ENODEV; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -ENODEV; + + redriver = i2c_get_clientdata(client); + if (!redriver) + return -EINVAL; + + /* 1. no operation in recovery mode. + * 2. there is case for 4 lane display, first report usb mode, + * second call usb release super speed lanes, + * then stop usb host and call this disconnect, + * it should not disable chip. + * 3. if already disabled, no need to disable again. + */ + if ((redriver->op_mode == OP_MODE_DEFAULT) || + (redriver->op_mode == OP_MODE_DP) || + (redriver->op_mode == OP_MODE_NONE)) + return 0; + + dev_dbg(redriver->dev, "op mode %s -> %s\n", + OPMODESTR(redriver->op_mode), OPMODESTR(OP_MODE_NONE)); + + redriver->op_mode = OP_MODE_NONE; + + ssusb_redriver_gen_dev_set(redriver); + + return 0; +} +EXPORT_SYMBOL(redriver_notify_disconnect); + int redriver_release_usb_lanes(struct device_node *node) { struct ssusb_redriver *redriver; struct i2c_client *client; if (!node) - return -EINVAL; + return -ENODEV; client = of_find_i2c_device_by_node(node); if (!client) - return -EINVAL; + return -ENODEV; redriver = i2c_get_clientdata(client); + if (!redriver) + return -EINVAL; if (redriver->op_mode == OP_MODE_DP) return 0; @@ -542,13 +634,15 @@ int redriver_gadget_pullup(struct device_node *node, int is_on) u8 val; if (!node) - return -EINVAL; + return -ENODEV; client = of_find_i2c_device_by_node(node); if (!client) - return -EINVAL; + return -ENODEV; redriver = i2c_get_clientdata(client); + if (!redriver) + return -EINVAL; /* * when redriver connect to a USB hub, and do adb root operation, diff --git a/include/linux/usb/redriver.h b/include/linux/usb/redriver.h index 13fb97a97b54..2ad09e9a4d57 100644 --- a/include/linux/usb/redriver.h +++ b/include/linux/usb/redriver.h @@ -10,6 +10,8 @@ int redriver_release_usb_lanes(struct device_node *node); int redriver_gadget_pullup(struct device_node *node, int is_on); +int redriver_notify_connect(struct device_node *node); +int redriver_notify_disconnect(struct device_node *node); #else @@ -23,6 +25,16 @@ static inline int redriver_gadget_pullup(struct device_node *node, int is_on) return 0; } +static inline int redriver_notify_connect(struct device_node *node) +{ + return 0; +} + +static inline int redriver_notify_disconnect(struct device_node *node) +{ + return 0; +} + #endif #endif /*__LINUX_USB_REDRIVER_H */