Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: fsa4480: rework mux & switch setup to handle more states

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>
Tested-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20230614-topic-sm8550-upstream-type-c-audio-v1-2-15a92565146b@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Neil Armstrong and committed by
Greg Kroah-Hartman
c7054c31 25a2bc21

+73 -34
+73 -34
drivers/usb/typec/mux/fsa4480.c
··· 46 46 47 47 struct regmap *regmap; 48 48 49 + enum typec_orientation orientation; 50 + unsigned long mode; 51 + unsigned int svid; 52 + 49 53 u8 cur_enable; 50 - u8 cur_select; 51 54 }; 52 55 53 56 static const struct regmap_config fsa4480_regmap_config = { ··· 61 58 .disable_locking = true, 62 59 }; 63 60 64 - static int fsa4480_switch_set(struct typec_switch_dev *sw, 65 - enum typec_orientation orientation) 61 + static int fsa4480_set(struct fsa4480 *fsa) 66 62 { 67 - struct fsa4480 *fsa = typec_switch_get_drvdata(sw); 68 - u8 new_sel; 63 + bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE); 64 + u8 enable = FSA4480_ENABLE_DEVICE; 65 + u8 sel = 0; 69 66 70 - mutex_lock(&fsa->lock); 71 - new_sel = FSA4480_SEL_USB; 72 - if (orientation == TYPEC_ORIENTATION_REVERSE) 73 - new_sel |= FSA4480_SEL_SBU_REVERSE; 67 + /* USB Mode */ 68 + if (fsa->mode < TYPEC_STATE_MODAL || 69 + (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 || 70 + fsa->mode == TYPEC_MODE_USB3))) { 71 + enable |= FSA4480_ENABLE_USB; 72 + sel = FSA4480_SEL_USB; 73 + } else if (fsa->svid) { 74 + switch (fsa->mode) { 75 + /* DP Only */ 76 + case TYPEC_DP_STATE_C: 77 + case TYPEC_DP_STATE_E: 78 + enable |= FSA4480_ENABLE_SBU; 79 + if (reverse) 80 + sel = FSA4480_SEL_SBU_REVERSE; 81 + break; 74 82 75 - if (new_sel == fsa->cur_select) 76 - goto out_unlock; 83 + /* DP + USB */ 84 + case TYPEC_DP_STATE_D: 85 + case TYPEC_DP_STATE_F: 86 + enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU; 87 + sel = FSA4480_SEL_USB; 88 + if (reverse) 89 + sel |= FSA4480_SEL_SBU_REVERSE; 90 + break; 91 + 92 + default: 93 + return -EOPNOTSUPP; 94 + } 95 + } else 96 + return -EOPNOTSUPP; 77 97 78 98 if (fsa->cur_enable & FSA4480_ENABLE_SBU) { 79 99 /* Disable SBU output while re-configuring the switch */ ··· 107 81 usleep_range(35, 1000); 108 82 } 109 83 110 - regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, new_sel); 111 - fsa->cur_select = new_sel; 84 + regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel); 85 + regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable); 112 86 113 - if (fsa->cur_enable & FSA4480_ENABLE_SBU) { 114 - regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable); 115 - 87 + if (enable & FSA4480_ENABLE_SBU) { 116 88 /* 15us to allow the SBU switch to turn on again */ 117 89 usleep_range(15, 1000); 118 90 } 119 91 120 - out_unlock: 121 - mutex_unlock(&fsa->lock); 92 + fsa->cur_enable = enable; 122 93 123 94 return 0; 95 + } 96 + 97 + static int fsa4480_switch_set(struct typec_switch_dev *sw, 98 + enum typec_orientation orientation) 99 + { 100 + struct fsa4480 *fsa = typec_switch_get_drvdata(sw); 101 + int ret = 0; 102 + 103 + mutex_lock(&fsa->lock); 104 + 105 + if (fsa->orientation != orientation) { 106 + fsa->orientation = orientation; 107 + 108 + ret = fsa4480_set(fsa); 109 + } 110 + 111 + mutex_unlock(&fsa->lock); 112 + 113 + return ret; 124 114 } 125 115 126 116 static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) 127 117 { 128 118 struct fsa4480 *fsa = typec_mux_get_drvdata(mux); 129 - u8 new_enable; 119 + int ret = 0; 130 120 131 121 mutex_lock(&fsa->lock); 132 122 133 - new_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB; 134 - if (state->mode >= TYPEC_DP_STATE_A) 135 - new_enable |= FSA4480_ENABLE_SBU; 123 + if (fsa->mode != state->mode) { 124 + fsa->mode = state->mode; 136 125 137 - if (new_enable == fsa->cur_enable) 138 - goto out_unlock; 126 + if (state->alt) 127 + fsa->svid = state->alt->svid; 128 + else 129 + fsa->svid = 0; // No SVID 139 130 140 - regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, new_enable); 141 - fsa->cur_enable = new_enable; 142 - 143 - if (new_enable & FSA4480_ENABLE_SBU) { 144 - /* 15us to allow the SBU switch to turn off */ 145 - usleep_range(15, 1000); 131 + ret = fsa4480_set(fsa); 146 132 } 147 133 148 - out_unlock: 149 134 mutex_unlock(&fsa->lock); 150 135 151 - return 0; 136 + return ret; 152 137 } 153 138 154 139 static int fsa4480_probe(struct i2c_client *client) ··· 180 143 if (IS_ERR(fsa->regmap)) 181 144 return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n"); 182 145 146 + /* Safe mode */ 183 147 fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB; 184 - fsa->cur_select = FSA4480_SEL_USB; 148 + fsa->mode = TYPEC_STATE_SAFE; 149 + fsa->orientation = TYPEC_ORIENTATION_NONE; 185 150 186 151 /* set default settings */ 187 152 regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00); ··· 195 156 regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00); 196 157 regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00); 197 158 regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09); 198 - regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, fsa->cur_select); 159 + regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB); 199 160 regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable); 200 161 201 162 sw_desc.drvdata = fsa;