Skip to content

Commit cf07c55

Browse files
lweiss-fairphonegregkh
authored andcommitted
usb: typec: fsa4480: Add support to swap SBU orientation
On some hardware designs the AUX+/- lanes are connected reversed to SBU1/2 compared to the expected design by FSA4480. Made more complicated, the otherwise compatible Orient-Chip OCP96011 expects the lanes to be connected reversed compared to FSA4480. * FSA4480 block diagram shows AUX+ connected to SBU2 and AUX- to SBU1. * OCP96011 block diagram shows AUX+ connected to SBU1 and AUX- to SBU2. So if OCP96011 is used as drop-in for FSA4480 then the orientation handling in the driver needs to be reversed to match the expectation of the OCP96011 hardware. Support parsing the data-lanes parameter in the endpoint node to swap this in the driver. The parse_data_lanes_mapping function is mostly taken from nb7vpq904m.c. Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> Link: https://lore.kernel.org/r/20231020-fsa4480-swap-v2-2-9a7f9bb59873@fairphone.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent fad89aa commit cf07c55

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

drivers/usb/typec/mux/fsa4480.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct fsa4480 {
6060
unsigned int svid;
6161

6262
u8 cur_enable;
63+
bool swap_sbu_lanes;
6364
};
6465

6566
static const struct regmap_config fsa4480_regmap_config = {
@@ -76,6 +77,9 @@ static int fsa4480_set(struct fsa4480 *fsa)
7677
u8 enable = FSA4480_ENABLE_DEVICE;
7778
u8 sel = 0;
7879

80+
if (fsa->swap_sbu_lanes)
81+
reverse = !reverse;
82+
7983
/* USB Mode */
8084
if (fsa->mode < TYPEC_STATE_MODAL ||
8185
(!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
@@ -179,12 +183,75 @@ static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *st
179183
return ret;
180184
}
181185

186+
enum {
187+
NORMAL_LANE_MAPPING,
188+
INVERT_LANE_MAPPING,
189+
};
190+
191+
#define DATA_LANES_COUNT 2
192+
193+
static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
194+
[NORMAL_LANE_MAPPING] = { 0, 1 },
195+
[INVERT_LANE_MAPPING] = { 1, 0 },
196+
};
197+
198+
static int fsa4480_parse_data_lanes_mapping(struct fsa4480 *fsa)
199+
{
200+
struct fwnode_handle *ep;
201+
u32 data_lanes[DATA_LANES_COUNT];
202+
int ret, i, j;
203+
204+
ep = fwnode_graph_get_next_endpoint(dev_fwnode(&fsa->client->dev), NULL);
205+
if (!ep)
206+
return 0;
207+
208+
ret = fwnode_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
209+
if (ret == -EINVAL)
210+
/* Property isn't here, consider default mapping */
211+
goto out_done;
212+
if (ret) {
213+
dev_err(&fsa->client->dev, "invalid data-lanes property: %d\n", ret);
214+
goto out_error;
215+
}
216+
217+
for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
218+
for (j = 0; j < DATA_LANES_COUNT; j++) {
219+
if (data_lanes[j] != supported_data_lane_mapping[i][j])
220+
break;
221+
}
222+
223+
if (j == DATA_LANES_COUNT)
224+
break;
225+
}
226+
227+
switch (i) {
228+
case NORMAL_LANE_MAPPING:
229+
break;
230+
case INVERT_LANE_MAPPING:
231+
fsa->swap_sbu_lanes = true;
232+
break;
233+
default:
234+
dev_err(&fsa->client->dev, "invalid data-lanes mapping\n");
235+
ret = -EINVAL;
236+
goto out_error;
237+
}
238+
239+
out_done:
240+
ret = 0;
241+
242+
out_error:
243+
fwnode_handle_put(ep);
244+
245+
return ret;
246+
}
247+
182248
static int fsa4480_probe(struct i2c_client *client)
183249
{
184250
struct device *dev = &client->dev;
185251
struct typec_switch_desc sw_desc = { };
186252
struct typec_mux_desc mux_desc = { };
187253
struct fsa4480 *fsa;
254+
int ret;
188255

189256
fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL);
190257
if (!fsa)
@@ -193,6 +260,10 @@ static int fsa4480_probe(struct i2c_client *client)
193260
fsa->client = client;
194261
mutex_init(&fsa->lock);
195262

263+
ret = fsa4480_parse_data_lanes_mapping(fsa);
264+
if (ret)
265+
return ret;
266+
196267
fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
197268
if (IS_ERR(fsa->regmap))
198269
return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");

0 commit comments

Comments
 (0)