This serie enables Audio Accessory mode support on the FSA4480
USB Type-C Analog Audio Switch.
In order to get the proper MUX state, also let's make UCSI
call type_set_mode() on partner changes to propagate the
Accessory and USB modes.
Signed-off-by: Neil Armstrong <[email protected]>
---
Neil Armstrong (3):
usb: typec: ucsi: call typec_set_mode on non-altmode partner change
usb: typec: fsa4480: rework mux & switch setup to handle more states
usb: typec: fsa4480: add support for Audio Accessory Mode
drivers/usb/typec/mux/fsa4480.c | 126 +++++++++++++++++++++++++++++-----------
drivers/usb/typec/ucsi/ucsi.c | 17 ++++++
2 files changed, 108 insertions(+), 35 deletions(-)
---
base-commit: 858fd168a95c5b9669aac8db6c14a9aeab446375
change-id: 20230614-topic-sm8550-upstream-type-c-audio-2ccdf6d18896
Best regards,
--
Neil Armstrong <[email protected]>
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 <[email protected]>
---
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
The FSA4480 Type-C switch supports switching the Audio R/L,
AGND and MIC signals to the USB-C DP/DM and SBU1/2 to support
the Audio Accessory Mode.
The FSA4480 has an integrated Audio jack detection mechanism
to automatically mux the AGND, MIX and Sense to the correct
SBU lines to support 3 pole and both 4 pole TRRS pinouts.
Signed-off-by: Neil Armstrong <[email protected]>
---
drivers/usb/typec/mux/fsa4480.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c
index b2913594a58f..45f5683b7d81 100644
--- a/drivers/usb/typec/mux/fsa4480.c
+++ b/drivers/usb/typec/mux/fsa4480.c
@@ -25,15 +25,24 @@
#define FSA4480_DELAY_L_MIC 0x0e
#define FSA4480_DELAY_L_SENSE 0x0f
#define FSA4480_DELAY_L_AGND 0x10
+#define FSA4480_FUNCTION_ENABLE 0x12
#define FSA4480_RESET 0x1e
#define FSA4480_MAX_REGISTER 0x1f
#define FSA4480_ENABLE_DEVICE BIT(7)
#define FSA4480_ENABLE_SBU GENMASK(6, 5)
#define FSA4480_ENABLE_USB GENMASK(4, 3)
+#define FSA4480_ENABLE_SENSE BIT(2)
+#define FSA4480_ENABLE_MIC BIT(1)
+#define FSA4480_ENABLE_AGND BIT(0)
#define FSA4480_SEL_SBU_REVERSE GENMASK(6, 5)
#define FSA4480_SEL_USB GENMASK(4, 3)
+#define FSA4480_SEL_SENSE BIT(2)
+#define FSA4480_SEL_MIC BIT(1)
+#define FSA4480_SEL_AGND BIT(0)
+
+#define FSA4480_ENABLE_AUTO_JACK_DETECT BIT(0)
struct fsa4480 {
struct i2c_client *client;
@@ -95,6 +104,9 @@ static int fsa4480_set(struct fsa4480 *fsa)
default:
return -EOPNOTSUPP;
}
+ } else if (fsa->mode == TYPEC_MODE_AUDIO) {
+ /* Audio Accessory Mode, setup to auto Jack Detection */
+ enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_AGND;
} else
return -EOPNOTSUPP;
@@ -110,6 +122,11 @@ static int fsa4480_set(struct fsa4480 *fsa)
regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
+ /* Start AUDIO JACK DETECTION to setup MIC, AGND & Sense muxes */
+ if (enable & FSA4480_ENABLE_AGND)
+ regmap_write(fsa->regmap, FSA4480_FUNCTION_ENABLE,
+ FSA4480_ENABLE_AUTO_JACK_DETECT);
+
if (enable & FSA4480_ENABLE_SBU) {
/* 15us to allow the SBU switch to turn on again */
usleep_range(15, 1000);
--
2.34.1
Add support for calling typec_set_mode() for the DEBUG, AUDIO
accessory modes.
Let's also call typec_set_mode() for USB as default and SAFE
when partner is disconnected.
The USB state is only called when ALT mode is specifically
not specified by the partner status flags in order
to leave the altmode handlers setup the proper mode to
switches, muxes and retimers.
Signed-off-by: Neil Armstrong <[email protected]>
---
drivers/usb/typec/ucsi/ucsi.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 2b472ec01dc4..44f43cdea5c1 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -809,6 +809,23 @@ static void ucsi_partner_change(struct ucsi_connector *con)
break;
}
+ if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
+ switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
+ typec_set_mode(con->port, TYPEC_MODE_DEBUG);
+ break;
+ case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
+ typec_set_mode(con->port, TYPEC_MODE_AUDIO);
+ break;
+ default:
+ if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) ==
+ UCSI_CONSTAT_PARTNER_FLAG_USB)
+ typec_set_mode(con->port, TYPEC_STATE_USB);
+ }
+ } else {
+ typec_set_mode(con->port, TYPEC_STATE_SAFE);
+ }
+
/* Only notify USB controller if partner supports USB data */
if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
u_role = USB_ROLE_NONE;
--
2.34.1
On 14/06/2023 15:10, Neil Armstrong wrote:
> Add support for calling typec_set_mode() for the DEBUG, AUDIO
> accessory modes.
>
> Let's also call typec_set_mode() for USB as default and SAFE
> when partner is disconnected.
>
> The USB state is only called when ALT mode is specifically
> not specified by the partner status flags in order
> to leave the altmode handlers setup the proper mode to
> switches, muxes and retimers.
>
Tested-by: Krzysztof Kozlowski <[email protected]>
Best regards,
Krzysztof
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 <[email protected]>
Best regards,
Krzysztof
On 14/06/2023 15:10, Neil Armstrong wrote:
> The FSA4480 Type-C switch supports switching the Audio R/L,
> AGND and MIC signals to the USB-C DP/DM and SBU1/2 to support
> the Audio Accessory Mode.
>
> The FSA4480 has an integrated Audio jack detection mechanism
> to automatically mux the AGND, MIX and Sense to the correct
> SBU lines to support 3 pole and both 4 pole TRRS pinouts.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
Tested-by: Krzysztof Kozlowski <[email protected]>
Best regards,
Krzysztof
Hi Neil,
Sorry to keep you waiting.
On Wed, Jun 14, 2023 at 03:10:39PM +0200, Neil Armstrong wrote:
> Add support for calling typec_set_mode() for the DEBUG, AUDIO
> accessory modes.
>
> Let's also call typec_set_mode() for USB as default and SAFE
> when partner is disconnected.
>
> The USB state is only called when ALT mode is specifically
> not specified by the partner status flags in order
> to leave the altmode handlers setup the proper mode to
> switches, muxes and retimers.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> drivers/usb/typec/ucsi/ucsi.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> index 2b472ec01dc4..44f43cdea5c1 100644
> --- a/drivers/usb/typec/ucsi/ucsi.c
> +++ b/drivers/usb/typec/ucsi/ucsi.c
> @@ -809,6 +809,23 @@ static void ucsi_partner_change(struct ucsi_connector *con)
> break;
> }
>
> + if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
> + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
> + case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
> + typec_set_mode(con->port, TYPEC_MODE_DEBUG);
> + break;
> + case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
> + typec_set_mode(con->port, TYPEC_MODE_AUDIO);
> + break;
> + default:
> + if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) ==
> + UCSI_CONSTAT_PARTNER_FLAG_USB)
> + typec_set_mode(con->port, TYPEC_STATE_USB);
> + }
> + } else {
> + typec_set_mode(con->port, TYPEC_STATE_SAFE);
> + }
Can you do that (set safe mode) in ucsi_unregister_partner() instead?
thanks,
--
heikki
On Wed, Jun 14, 2023 at 03:10:41PM +0200, Neil Armstrong wrote:
> The FSA4480 Type-C switch supports switching the Audio R/L,
> AGND and MIC signals to the USB-C DP/DM and SBU1/2 to support
> the Audio Accessory Mode.
>
> The FSA4480 has an integrated Audio jack detection mechanism
> to automatically mux the AGND, MIX and Sense to the correct
> SBU lines to support 3 pole and both 4 pole TRRS pinouts.
>
> Signed-off-by: Neil Armstrong <[email protected]>
Acked-by: Heikki Krogerus <[email protected]>
> ---
> drivers/usb/typec/mux/fsa4480.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c
> index b2913594a58f..45f5683b7d81 100644
> --- a/drivers/usb/typec/mux/fsa4480.c
> +++ b/drivers/usb/typec/mux/fsa4480.c
> @@ -25,15 +25,24 @@
> #define FSA4480_DELAY_L_MIC 0x0e
> #define FSA4480_DELAY_L_SENSE 0x0f
> #define FSA4480_DELAY_L_AGND 0x10
> +#define FSA4480_FUNCTION_ENABLE 0x12
> #define FSA4480_RESET 0x1e
> #define FSA4480_MAX_REGISTER 0x1f
>
> #define FSA4480_ENABLE_DEVICE BIT(7)
> #define FSA4480_ENABLE_SBU GENMASK(6, 5)
> #define FSA4480_ENABLE_USB GENMASK(4, 3)
> +#define FSA4480_ENABLE_SENSE BIT(2)
> +#define FSA4480_ENABLE_MIC BIT(1)
> +#define FSA4480_ENABLE_AGND BIT(0)
>
> #define FSA4480_SEL_SBU_REVERSE GENMASK(6, 5)
> #define FSA4480_SEL_USB GENMASK(4, 3)
> +#define FSA4480_SEL_SENSE BIT(2)
> +#define FSA4480_SEL_MIC BIT(1)
> +#define FSA4480_SEL_AGND BIT(0)
> +
> +#define FSA4480_ENABLE_AUTO_JACK_DETECT BIT(0)
>
> struct fsa4480 {
> struct i2c_client *client;
> @@ -95,6 +104,9 @@ static int fsa4480_set(struct fsa4480 *fsa)
> default:
> return -EOPNOTSUPP;
> }
> + } else if (fsa->mode == TYPEC_MODE_AUDIO) {
> + /* Audio Accessory Mode, setup to auto Jack Detection */
> + enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_AGND;
> } else
> return -EOPNOTSUPP;
>
> @@ -110,6 +122,11 @@ static int fsa4480_set(struct fsa4480 *fsa)
> regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
> regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
>
> + /* Start AUDIO JACK DETECTION to setup MIC, AGND & Sense muxes */
> + if (enable & FSA4480_ENABLE_AGND)
> + regmap_write(fsa->regmap, FSA4480_FUNCTION_ENABLE,
> + FSA4480_ENABLE_AUTO_JACK_DETECT);
> +
> if (enable & FSA4480_ENABLE_SBU) {
> /* 15us to allow the SBU switch to turn on again */
> usleep_range(15, 1000);
thanks,
--
heikki
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 <[email protected]>
Reviewed-by: Heikki Krogerus <[email protected]>
> ---
> 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
--
heikki
Hi,
On 26/06/2023 10:12, Heikki Krogerus wrote:
> Hi Neil,
>
> Sorry to keep you waiting.
No problem, thanks for reviewing my patches!
>
> On Wed, Jun 14, 2023 at 03:10:39PM +0200, Neil Armstrong wrote:
>> Add support for calling typec_set_mode() for the DEBUG, AUDIO
>> accessory modes.
>>
>> Let's also call typec_set_mode() for USB as default and SAFE
>> when partner is disconnected.
>>
>> The USB state is only called when ALT mode is specifically
>> not specified by the partner status flags in order
>> to leave the altmode handlers setup the proper mode to
>> switches, muxes and retimers.
>>
>> Signed-off-by: Neil Armstrong <[email protected]>
>> ---
>> drivers/usb/typec/ucsi/ucsi.c | 17 +++++++++++++++++
>> 1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
>> index 2b472ec01dc4..44f43cdea5c1 100644
>> --- a/drivers/usb/typec/ucsi/ucsi.c
>> +++ b/drivers/usb/typec/ucsi/ucsi.c
>> @@ -809,6 +809,23 @@ static void ucsi_partner_change(struct ucsi_connector *con)
>> break;
>> }
>>
>> + if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
>> + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
>> + case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
>> + typec_set_mode(con->port, TYPEC_MODE_DEBUG);
>> + break;
>> + case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
>> + typec_set_mode(con->port, TYPEC_MODE_AUDIO);
>> + break;
>> + default:
>> + if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) ==
>> + UCSI_CONSTAT_PARTNER_FLAG_USB)
>> + typec_set_mode(con->port, TYPEC_STATE_USB);
>> + }
>> + } else {
>> + typec_set_mode(con->port, TYPEC_STATE_SAFE);
>> + }
>
> Can you do that (set safe mode) in ucsi_unregister_partner() instead?
It seems greg already landed the patch into usb-next, but I can send a fix to
move it to unregister
Neil
>
> thanks,
>
On Mon, Jun 26, 2023 at 03:23:11PM +0200, Neil Armstrong wrote:
> Hi,
>
> On 26/06/2023 10:12, Heikki Krogerus wrote:
> > Hi Neil,
> >
> > Sorry to keep you waiting.
>
> No problem, thanks for reviewing my patches!
>
> >
> > On Wed, Jun 14, 2023 at 03:10:39PM +0200, Neil Armstrong wrote:
> > > Add support for calling typec_set_mode() for the DEBUG, AUDIO
> > > accessory modes.
> > >
> > > Let's also call typec_set_mode() for USB as default and SAFE
> > > when partner is disconnected.
> > >
> > > The USB state is only called when ALT mode is specifically
> > > not specified by the partner status flags in order
> > > to leave the altmode handlers setup the proper mode to
> > > switches, muxes and retimers.
> > >
> > > Signed-off-by: Neil Armstrong <[email protected]>
> > > ---
> > > drivers/usb/typec/ucsi/ucsi.c | 17 +++++++++++++++++
> > > 1 file changed, 17 insertions(+)
> > >
> > > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
> > > index 2b472ec01dc4..44f43cdea5c1 100644
> > > --- a/drivers/usb/typec/ucsi/ucsi.c
> > > +++ b/drivers/usb/typec/ucsi/ucsi.c
> > > @@ -809,6 +809,23 @@ static void ucsi_partner_change(struct ucsi_connector *con)
> > > break;
> > > }
> > > + if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
> > > + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
> > > + case UCSI_CONSTAT_PARTNER_TYPE_DEBUG:
> > > + typec_set_mode(con->port, TYPEC_MODE_DEBUG);
> > > + break;
> > > + case UCSI_CONSTAT_PARTNER_TYPE_AUDIO:
> > > + typec_set_mode(con->port, TYPEC_MODE_AUDIO);
> > > + break;
> > > + default:
> > > + if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) ==
> > > + UCSI_CONSTAT_PARTNER_FLAG_USB)
> > > + typec_set_mode(con->port, TYPEC_STATE_USB);
> > > + }
> > > + } else {
> > > + typec_set_mode(con->port, TYPEC_STATE_SAFE);
> > > + }
> >
> > Can you do that (set safe mode) in ucsi_unregister_partner() instead?
>
> It seems greg already landed the patch into usb-next, but I can send a fix to
> move it to unregister
Yes please.