diff mbox series

[2/3] usb: typec: fsa4480: rework mux & switch setup to handle more states

Message ID 20230614-topic-sm8550-upstream-type-c-audio-v1-2-15a92565146b@linaro.org (mailing list archive)
State Accepted
Commit c7054c31c1c94dbfe0ddf7c327f72f020d47c6c9
Headers show
Series typec: support Audio Accessory mode on FSA4480 | expand

Commit Message

Neil Armstrong June 14, 2023, 1:10 p.m. UTC
In order to handle the Audio Accessory mode, refactor the mux
and switch setup in a single function.

The refactor will help add new states and make the process
simpler to understand.

Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
---
 drivers/usb/typec/mux/fsa4480.c | 111 +++++++++++++++++++++++++++-------------
 1 file changed, 75 insertions(+), 36 deletions(-)

Comments

Krzysztof Kozlowski June 14, 2023, 1:12 p.m. UTC | #1
On 14/06/2023 15:10, Neil Armstrong wrote:
> In order to handle the Audio Accessory mode, refactor the mux
> and switch setup in a single function.
> 
> The refactor will help add new states and make the process
> simpler to understand.
> 


Tested-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof
Heikki Krogerus June 26, 2023, 8:30 a.m. UTC | #2
On Wed, Jun 14, 2023 at 03:10:40PM +0200, Neil Armstrong wrote:
> In order to handle the Audio Accessory mode, refactor the mux
> and switch setup in a single function.
> 
> The refactor will help add new states and make the process
> simpler to understand.
> 
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
>  drivers/usb/typec/mux/fsa4480.c | 111 +++++++++++++++++++++++++++-------------
>  1 file changed, 75 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c
> index d6495e533e58..b2913594a58f 100644
> --- a/drivers/usb/typec/mux/fsa4480.c
> +++ b/drivers/usb/typec/mux/fsa4480.c
> @@ -46,8 +46,11 @@ struct fsa4480 {
>  
>  	struct regmap *regmap;
>  
> +	enum typec_orientation orientation;
> +	unsigned long mode;
> +	unsigned int svid;
> +
>  	u8 cur_enable;
> -	u8 cur_select;
>  };
>  
>  static const struct regmap_config fsa4480_regmap_config = {
> @@ -58,19 +61,42 @@ static const struct regmap_config fsa4480_regmap_config = {
>  	.disable_locking = true,
>  };
>  
> -static int fsa4480_switch_set(struct typec_switch_dev *sw,
> -			      enum typec_orientation orientation)
> +static int fsa4480_set(struct fsa4480 *fsa)
>  {
> -	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
> -	u8 new_sel;
> -
> -	mutex_lock(&fsa->lock);
> -	new_sel = FSA4480_SEL_USB;
> -	if (orientation == TYPEC_ORIENTATION_REVERSE)
> -		new_sel |= FSA4480_SEL_SBU_REVERSE;
> -
> -	if (new_sel == fsa->cur_select)
> -		goto out_unlock;
> +	bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE);
> +	u8 enable = FSA4480_ENABLE_DEVICE;
> +	u8 sel = 0;
> +
> +	/* USB Mode */
> +	if (fsa->mode < TYPEC_STATE_MODAL ||
> +	    (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
> +			    fsa->mode == TYPEC_MODE_USB3))) {
> +		enable |= FSA4480_ENABLE_USB;
> +		sel = FSA4480_SEL_USB;
> +	} else if (fsa->svid) {
> +		switch (fsa->mode) {
> +		/* DP Only */
> +		case TYPEC_DP_STATE_C:
> +		case TYPEC_DP_STATE_E:
> +			enable |= FSA4480_ENABLE_SBU;
> +			if (reverse)
> +				sel = FSA4480_SEL_SBU_REVERSE;
> +			break;
> +
> +		/* DP + USB */
> +		case TYPEC_DP_STATE_D:
> +		case TYPEC_DP_STATE_F:
> +			enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU;
> +			sel = FSA4480_SEL_USB;
> +			if (reverse)
> +				sel |= FSA4480_SEL_SBU_REVERSE;
> +			break;
> +
> +		default:
> +			return -EOPNOTSUPP;
> +		}
> +	} else
> +		return -EOPNOTSUPP;
>  
>  	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
>  		/* Disable SBU output while re-configuring the switch */
> @@ -81,48 +107,59 @@ static int fsa4480_switch_set(struct typec_switch_dev *sw,
>  		usleep_range(35, 1000);
>  	}
>  
> -	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, new_sel);
> -	fsa->cur_select = new_sel;
> -
> -	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
> -		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
> +	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
> +	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
>  
> +	if (enable & FSA4480_ENABLE_SBU) {
>  		/* 15us to allow the SBU switch to turn on again */
>  		usleep_range(15, 1000);
>  	}
>  
> -out_unlock:
> -	mutex_unlock(&fsa->lock);
> +	fsa->cur_enable = enable;
>  
>  	return 0;
>  }
>  
> +static int fsa4480_switch_set(struct typec_switch_dev *sw,
> +			      enum typec_orientation orientation)
> +{
> +	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
> +	int ret = 0;
> +
> +	mutex_lock(&fsa->lock);
> +
> +	if (fsa->orientation != orientation) {
> +		fsa->orientation = orientation;
> +
> +		ret = fsa4480_set(fsa);
> +	}
> +
> +	mutex_unlock(&fsa->lock);
> +
> +	return ret;
> +}
> +
>  static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
>  {
>  	struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
> -	u8 new_enable;
> +	int ret = 0;
>  
>  	mutex_lock(&fsa->lock);
>  
> -	new_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
> -	if (state->mode >= TYPEC_DP_STATE_A)
> -		new_enable |= FSA4480_ENABLE_SBU;
> +	if (fsa->mode != state->mode) {
> +		fsa->mode = state->mode;
>  
> -	if (new_enable == fsa->cur_enable)
> -		goto out_unlock;
> +		if (state->alt)
> +			fsa->svid = state->alt->svid;
> +		else
> +			fsa->svid = 0; // No SVID
>  
> -	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, new_enable);
> -	fsa->cur_enable = new_enable;
> -
> -	if (new_enable & FSA4480_ENABLE_SBU) {
> -		/* 15us to allow the SBU switch to turn off */
> -		usleep_range(15, 1000);
> +		ret = fsa4480_set(fsa);
>  	}
>  
> -out_unlock:
>  	mutex_unlock(&fsa->lock);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  static int fsa4480_probe(struct i2c_client *client)
> @@ -143,8 +180,10 @@ static int fsa4480_probe(struct i2c_client *client)
>  	if (IS_ERR(fsa->regmap))
>  		return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
>  
> +	/* Safe mode */
>  	fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
> -	fsa->cur_select = FSA4480_SEL_USB;
> +	fsa->mode = TYPEC_STATE_SAFE;
> +	fsa->orientation = TYPEC_ORIENTATION_NONE;
>  
>  	/* set default settings */
>  	regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00);
> @@ -156,7 +195,7 @@ static int fsa4480_probe(struct i2c_client *client)
>  	regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00);
>  	regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00);
>  	regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09);
> -	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, fsa->cur_select);
> +	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB);
>  	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
>  
>  	sw_desc.drvdata = fsa;
> 
> -- 
> 2.34.1
diff mbox series

Patch

diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c
index d6495e533e58..b2913594a58f 100644
--- a/drivers/usb/typec/mux/fsa4480.c
+++ b/drivers/usb/typec/mux/fsa4480.c
@@ -46,8 +46,11 @@  struct fsa4480 {
 
 	struct regmap *regmap;
 
+	enum typec_orientation orientation;
+	unsigned long mode;
+	unsigned int svid;
+
 	u8 cur_enable;
-	u8 cur_select;
 };
 
 static const struct regmap_config fsa4480_regmap_config = {
@@ -58,19 +61,42 @@  static const struct regmap_config fsa4480_regmap_config = {
 	.disable_locking = true,
 };
 
-static int fsa4480_switch_set(struct typec_switch_dev *sw,
-			      enum typec_orientation orientation)
+static int fsa4480_set(struct fsa4480 *fsa)
 {
-	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
-	u8 new_sel;
-
-	mutex_lock(&fsa->lock);
-	new_sel = FSA4480_SEL_USB;
-	if (orientation == TYPEC_ORIENTATION_REVERSE)
-		new_sel |= FSA4480_SEL_SBU_REVERSE;
-
-	if (new_sel == fsa->cur_select)
-		goto out_unlock;
+	bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE);
+	u8 enable = FSA4480_ENABLE_DEVICE;
+	u8 sel = 0;
+
+	/* USB Mode */
+	if (fsa->mode < TYPEC_STATE_MODAL ||
+	    (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
+			    fsa->mode == TYPEC_MODE_USB3))) {
+		enable |= FSA4480_ENABLE_USB;
+		sel = FSA4480_SEL_USB;
+	} else if (fsa->svid) {
+		switch (fsa->mode) {
+		/* DP Only */
+		case TYPEC_DP_STATE_C:
+		case TYPEC_DP_STATE_E:
+			enable |= FSA4480_ENABLE_SBU;
+			if (reverse)
+				sel = FSA4480_SEL_SBU_REVERSE;
+			break;
+
+		/* DP + USB */
+		case TYPEC_DP_STATE_D:
+		case TYPEC_DP_STATE_F:
+			enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU;
+			sel = FSA4480_SEL_USB;
+			if (reverse)
+				sel |= FSA4480_SEL_SBU_REVERSE;
+			break;
+
+		default:
+			return -EOPNOTSUPP;
+		}
+	} else
+		return -EOPNOTSUPP;
 
 	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
 		/* Disable SBU output while re-configuring the switch */
@@ -81,48 +107,59 @@  static int fsa4480_switch_set(struct typec_switch_dev *sw,
 		usleep_range(35, 1000);
 	}
 
-	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, new_sel);
-	fsa->cur_select = new_sel;
-
-	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
-		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
+	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
+	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
 
+	if (enable & FSA4480_ENABLE_SBU) {
 		/* 15us to allow the SBU switch to turn on again */
 		usleep_range(15, 1000);
 	}
 
-out_unlock:
-	mutex_unlock(&fsa->lock);
+	fsa->cur_enable = enable;
 
 	return 0;
 }
 
+static int fsa4480_switch_set(struct typec_switch_dev *sw,
+			      enum typec_orientation orientation)
+{
+	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
+	int ret = 0;
+
+	mutex_lock(&fsa->lock);
+
+	if (fsa->orientation != orientation) {
+		fsa->orientation = orientation;
+
+		ret = fsa4480_set(fsa);
+	}
+
+	mutex_unlock(&fsa->lock);
+
+	return ret;
+}
+
 static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
 {
 	struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
-	u8 new_enable;
+	int ret = 0;
 
 	mutex_lock(&fsa->lock);
 
-	new_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
-	if (state->mode >= TYPEC_DP_STATE_A)
-		new_enable |= FSA4480_ENABLE_SBU;
+	if (fsa->mode != state->mode) {
+		fsa->mode = state->mode;
 
-	if (new_enable == fsa->cur_enable)
-		goto out_unlock;
+		if (state->alt)
+			fsa->svid = state->alt->svid;
+		else
+			fsa->svid = 0; // No SVID
 
-	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, new_enable);
-	fsa->cur_enable = new_enable;
-
-	if (new_enable & FSA4480_ENABLE_SBU) {
-		/* 15us to allow the SBU switch to turn off */
-		usleep_range(15, 1000);
+		ret = fsa4480_set(fsa);
 	}
 
-out_unlock:
 	mutex_unlock(&fsa->lock);
 
-	return 0;
+	return ret;
 }
 
 static int fsa4480_probe(struct i2c_client *client)
@@ -143,8 +180,10 @@  static int fsa4480_probe(struct i2c_client *client)
 	if (IS_ERR(fsa->regmap))
 		return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
 
+	/* Safe mode */
 	fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
-	fsa->cur_select = FSA4480_SEL_USB;
+	fsa->mode = TYPEC_STATE_SAFE;
+	fsa->orientation = TYPEC_ORIENTATION_NONE;
 
 	/* set default settings */
 	regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00);
@@ -156,7 +195,7 @@  static int fsa4480_probe(struct i2c_client *client)
 	regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00);
 	regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00);
 	regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09);
-	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, fsa->cur_select);
+	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB);
 	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
 
 	sw_desc.drvdata = fsa;