mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 19:13:47 +02:00
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>
This commit is contained in:
parent
fad89aa14c
commit
cf07c55f99
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user