Commit cf07c55f authored by Luca Weiss's avatar Luca Weiss Committed by Greg Kroah-Hartman

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: default avatarNeil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: default avatarLuca Weiss <luca.weiss@fairphone.com>
Link: https://lore.kernel.org/r/20231020-fsa4480-swap-v2-2-9a7f9bb59873@fairphone.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fad89aa1
......@@ -60,6 +60,7 @@ struct fsa4480 {
unsigned int svid;
u8 cur_enable;
bool swap_sbu_lanes;
};
static const struct regmap_config fsa4480_regmap_config = {
......@@ -76,6 +77,9 @@ static int fsa4480_set(struct fsa4480 *fsa)
u8 enable = FSA4480_ENABLE_DEVICE;
u8 sel = 0;
if (fsa->swap_sbu_lanes)
reverse = !reverse;
/* USB Mode */
if (fsa->mode < TYPEC_STATE_MODAL ||
(!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
return ret;
}
enum {
NORMAL_LANE_MAPPING,
INVERT_LANE_MAPPING,
};
#define DATA_LANES_COUNT 2
static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
[NORMAL_LANE_MAPPING] = { 0, 1 },
[INVERT_LANE_MAPPING] = { 1, 0 },
};
static int fsa4480_parse_data_lanes_mapping(struct fsa4480 *fsa)
{
struct fwnode_handle *ep;
u32 data_lanes[DATA_LANES_COUNT];
int ret, i, j;
ep = fwnode_graph_get_next_endpoint(dev_fwnode(&fsa->client->dev), NULL);
if (!ep)
return 0;
ret = fwnode_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
if (ret == -EINVAL)
/* Property isn't here, consider default mapping */
goto out_done;
if (ret) {
dev_err(&fsa->client->dev, "invalid data-lanes property: %d\n", ret);
goto out_error;
}
for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
for (j = 0; j < DATA_LANES_COUNT; j++) {
if (data_lanes[j] != supported_data_lane_mapping[i][j])
break;
}
if (j == DATA_LANES_COUNT)
break;
}
switch (i) {
case NORMAL_LANE_MAPPING:
break;
case INVERT_LANE_MAPPING:
fsa->swap_sbu_lanes = true;
break;
default:
dev_err(&fsa->client->dev, "invalid data-lanes mapping\n");
ret = -EINVAL;
goto out_error;
}
out_done:
ret = 0;
out_error:
fwnode_handle_put(ep);
return ret;
}
static int fsa4480_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct typec_switch_desc sw_desc = { };
struct typec_mux_desc mux_desc = { };
struct fsa4480 *fsa;
int ret;
fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL);
if (!fsa)
......@@ -193,6 +260,10 @@ static int fsa4480_probe(struct i2c_client *client)
fsa->client = client;
mutex_init(&fsa->lock);
ret = fsa4480_parse_data_lanes_mapping(fsa);
if (ret)
return ret;
fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
if (IS_ERR(fsa->regmap))
return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment