phy: phy-rockchip-inno-usb2: support muxed interrupts
The rk3568 usb2phy has a single muxed interrupt that handles all interrupts. Allow the driver to plug in only a single interrupt as necessary. Signed-off-by: Peter Geis <pgwipeout@gmail.com> Tested-by: Michael Riesch <michael.riesch@wolfvision.net> Link: https://lore.kernel.org/r/20211215210252.120923-6-pgwipeout@gmail.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
e6915e1acc
commit
ed2b5a8e6b
1 changed files with 119 additions and 49 deletions
|
@ -204,6 +204,7 @@ struct rockchip_usb2phy_port {
|
||||||
* @dcd_retries: The retry count used to track Data contact
|
* @dcd_retries: The retry count used to track Data contact
|
||||||
* detection process.
|
* detection process.
|
||||||
* @edev: extcon device for notification registration
|
* @edev: extcon device for notification registration
|
||||||
|
* @irq: muxed interrupt for single irq configuration
|
||||||
* @phy_cfg: phy register configuration, assigned by driver data.
|
* @phy_cfg: phy register configuration, assigned by driver data.
|
||||||
* @ports: phy port instance.
|
* @ports: phy port instance.
|
||||||
*/
|
*/
|
||||||
|
@ -218,6 +219,7 @@ struct rockchip_usb2phy {
|
||||||
enum power_supply_type chg_type;
|
enum power_supply_type chg_type;
|
||||||
u8 dcd_retries;
|
u8 dcd_retries;
|
||||||
struct extcon_dev *edev;
|
struct extcon_dev *edev;
|
||||||
|
int irq;
|
||||||
const struct rockchip_usb2phy_cfg *phy_cfg;
|
const struct rockchip_usb2phy_cfg *phy_cfg;
|
||||||
struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS];
|
struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS];
|
||||||
};
|
};
|
||||||
|
@ -926,6 +928,102 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct rockchip_usb2phy *rphy = data;
|
||||||
|
struct rockchip_usb2phy_port *rport;
|
||||||
|
irqreturn_t ret = IRQ_NONE;
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
for (index = 0; index < rphy->phy_cfg->num_ports; index++) {
|
||||||
|
rport = &rphy->ports[index];
|
||||||
|
if (!rport->phy)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Handle linestate irq for both otg port and host port */
|
||||||
|
ret = rockchip_usb2phy_linestate_irq(irq, rport);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy,
|
||||||
|
struct rockchip_usb2phy_port *rport,
|
||||||
|
struct device_node *child_np)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the usb2 phy used combined irq for otg and host port,
|
||||||
|
* don't need to init otg and host port irq separately.
|
||||||
|
*/
|
||||||
|
if (rphy->irq > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (rport->port_id) {
|
||||||
|
case USB2PHY_PORT_HOST:
|
||||||
|
rport->ls_irq = of_irq_get_byname(child_np, "linestate");
|
||||||
|
if (rport->ls_irq < 0) {
|
||||||
|
dev_err(rphy->dev, "no linestate irq provided\n");
|
||||||
|
return rport->ls_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
|
||||||
|
rockchip_usb2phy_linestate_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"rockchip_usb2phy", rport);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(rphy->dev, "failed to request linestate irq handle\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB2PHY_PORT_OTG:
|
||||||
|
/*
|
||||||
|
* Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
|
||||||
|
* interrupts muxed together, so probe the otg-mux interrupt first,
|
||||||
|
* if not found, then look for the regular interrupts one by one.
|
||||||
|
*/
|
||||||
|
rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux");
|
||||||
|
if (rport->otg_mux_irq > 0) {
|
||||||
|
ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq,
|
||||||
|
NULL,
|
||||||
|
rockchip_usb2phy_otg_mux_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"rockchip_usb2phy_otg",
|
||||||
|
rport);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(rphy->dev,
|
||||||
|
"failed to request otg-mux irq handle\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
|
||||||
|
if (rport->bvalid_irq < 0) {
|
||||||
|
dev_err(rphy->dev, "no vbus valid irq provided\n");
|
||||||
|
ret = rport->bvalid_irq;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq,
|
||||||
|
NULL,
|
||||||
|
rockchip_usb2phy_bvalid_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"rockchip_usb2phy_bvalid",
|
||||||
|
rport);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(rphy->dev,
|
||||||
|
"failed to request otg-bvalid irq handle\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
|
static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
|
||||||
struct rockchip_usb2phy_port *rport,
|
struct rockchip_usb2phy_port *rport,
|
||||||
struct device_node *child_np)
|
struct device_node *child_np)
|
||||||
|
@ -939,18 +1037,9 @@ static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
|
||||||
mutex_init(&rport->mutex);
|
mutex_init(&rport->mutex);
|
||||||
INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
|
INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
|
||||||
|
|
||||||
rport->ls_irq = of_irq_get_byname(child_np, "linestate");
|
ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
|
||||||
if (rport->ls_irq < 0) {
|
|
||||||
dev_err(rphy->dev, "no linestate irq provided\n");
|
|
||||||
return rport->ls_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
|
|
||||||
rockchip_usb2phy_linestate_irq,
|
|
||||||
IRQF_ONESHOT,
|
|
||||||
"rockchip_usb2phy", rport);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(rphy->dev, "failed to request linestate irq handle\n");
|
dev_err(rphy->dev, "failed to setup host irq\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,44 +1088,10 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
|
||||||
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
|
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
|
||||||
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
|
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
|
||||||
|
|
||||||
/*
|
ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np);
|
||||||
* Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
|
if (ret) {
|
||||||
* interrupts muxed together, so probe the otg-mux interrupt first,
|
dev_err(rphy->dev, "failed to init irq for host port\n");
|
||||||
* if not found, then look for the regular interrupts one by one.
|
goto out;
|
||||||
*/
|
|
||||||
rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux");
|
|
||||||
if (rport->otg_mux_irq > 0) {
|
|
||||||
ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq,
|
|
||||||
NULL,
|
|
||||||
rockchip_usb2phy_otg_mux_irq,
|
|
||||||
IRQF_ONESHOT,
|
|
||||||
"rockchip_usb2phy_otg",
|
|
||||||
rport);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(rphy->dev,
|
|
||||||
"failed to request otg-mux irq handle\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid");
|
|
||||||
if (rport->bvalid_irq < 0) {
|
|
||||||
dev_err(rphy->dev, "no vbus valid irq provided\n");
|
|
||||||
ret = rport->bvalid_irq;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq,
|
|
||||||
NULL,
|
|
||||||
rockchip_usb2phy_bvalid_irq,
|
|
||||||
IRQF_ONESHOT,
|
|
||||||
"rockchip_usb2phy_bvalid",
|
|
||||||
rport);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(rphy->dev,
|
|
||||||
"failed to request otg-bvalid irq handle\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IS_ERR(rphy->edev)) {
|
if (!IS_ERR(rphy->edev)) {
|
||||||
rport->event_nb.notifier_call = rockchip_otg_event;
|
rport->event_nb.notifier_call = rockchip_otg_event;
|
||||||
|
@ -1116,6 +1171,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||||
phy_cfgs = match->data;
|
phy_cfgs = match->data;
|
||||||
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
|
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
|
||||||
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
|
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
|
||||||
|
rphy->irq = platform_get_irq_optional(pdev, 0);
|
||||||
platform_set_drvdata(pdev, rphy);
|
platform_set_drvdata(pdev, rphy);
|
||||||
|
|
||||||
ret = rockchip_usb2phy_extcon_register(rphy);
|
ret = rockchip_usb2phy_extcon_register(rphy);
|
||||||
|
@ -1195,6 +1251,20 @@ next_child:
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
if (rphy->irq > 0) {
|
||||||
|
ret = devm_request_threaded_irq(rphy->dev, rphy->irq, NULL,
|
||||||
|
rockchip_usb2phy_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"rockchip_usb2phy",
|
||||||
|
rphy);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(rphy->dev,
|
||||||
|
"failed to request usb2phy irq handle\n");
|
||||||
|
goto put_child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(provider);
|
return PTR_ERR_OR_ZERO(provider);
|
||||||
|
|
||||||
put_child:
|
put_child:
|
||||||
|
|
Loading…
Add table
Reference in a new issue