diff options
Diffstat (limited to 'drivers/usb/typec/bus.c')
-rw-r--r-- | drivers/usb/typec/bus.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c index 74cb3c2ecb34..2e45eb479386 100644 --- a/drivers/usb/typec/bus.c +++ b/drivers/usb/typec/bus.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * Bus for USB Type-C Alternate Modes * * Copyright (C) 2018 Intel Corporation @@ -10,12 +10,23 @@ #include "bus.h" -static inline int typec_altmode_set_mux(struct altmode *alt, u8 state) +static inline int +typec_altmode_set_mux(struct altmode *alt, unsigned long conf, void *data) { - return alt->mux ? alt->mux->set(alt->mux, state) : 0; + struct typec_mux_state state; + + if (!alt->mux) + return 0; + + state.alt = &alt->adev; + state.mode = conf; + state.data = data; + + return alt->mux->set(alt->mux, &state); } -static int typec_altmode_set_state(struct typec_altmode *adev, int state) +static int typec_altmode_set_state(struct typec_altmode *adev, + unsigned long conf, void *data) { bool is_port = is_typec_port(adev->dev.parent); struct altmode *port_altmode; @@ -23,11 +34,11 @@ static int typec_altmode_set_state(struct typec_altmode *adev, int state) port_altmode = is_port ? to_altmode(adev) : to_altmode(adev)->partner; - ret = typec_altmode_set_mux(port_altmode, state); + ret = typec_altmode_set_mux(port_altmode, conf, data); if (ret) return ret; - blocking_notifier_call_chain(&port_altmode->nh, state, NULL); + blocking_notifier_call_chain(&port_altmode->nh, conf, NULL); return 0; } @@ -67,7 +78,7 @@ int typec_altmode_notify(struct typec_altmode *adev, is_port = is_typec_port(adev->dev.parent); partner = altmode->partner; - ret = typec_altmode_set_mux(is_port ? altmode : partner, (u8)conf); + ret = typec_altmode_set_mux(is_port ? altmode : partner, conf, data); if (ret) return ret; @@ -84,12 +95,14 @@ EXPORT_SYMBOL_GPL(typec_altmode_notify); /** * typec_altmode_enter - Enter Mode * @adev: The alternate mode + * @vdo: VDO for the Enter Mode command * * The alternate mode drivers use this function to enter mode. The port drivers * use this to inform the alternate mode drivers that the partner has initiated - * Enter Mode command. + * Enter Mode command. If the alternate mode does not require VDO, @vdo must be + * NULL. */ -int typec_altmode_enter(struct typec_altmode *adev) +int typec_altmode_enter(struct typec_altmode *adev, u32 *vdo) { struct altmode *partner = to_altmode(adev)->partner; struct typec_altmode *pdev = &partner->adev; @@ -101,13 +114,16 @@ int typec_altmode_enter(struct typec_altmode *adev) if (!pdev->ops || !pdev->ops->enter) return -EOPNOTSUPP; + if (is_typec_port(pdev->dev.parent) && !pdev->active) + return -EPERM; + /* Moving to USB Safe State */ - ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE); + ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL); if (ret) return ret; /* Enter Mode */ - return pdev->ops->enter(pdev); + return pdev->ops->enter(pdev, vdo); } EXPORT_SYMBOL_GPL(typec_altmode_enter); @@ -130,7 +146,7 @@ int typec_altmode_exit(struct typec_altmode *adev) return -EOPNOTSUPP; /* Moving to USB Safe State */ - ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE); + ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL); if (ret) return ret; @@ -383,7 +399,7 @@ static int typec_remove(struct device *dev) drv->remove(to_typec_altmode(dev)); if (adev->active) { - WARN_ON(typec_altmode_set_state(adev, TYPEC_STATE_SAFE)); + WARN_ON(typec_altmode_set_state(adev, TYPEC_STATE_SAFE, NULL)); typec_altmode_update_active(adev, false); } |