From patchwork Tue Dec 28 05:21:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 529387 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 281D9C433F5 for ; Tue, 28 Dec 2021 05:20:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234857AbhL1FU0 (ORCPT ); Tue, 28 Dec 2021 00:20:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48788 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234837AbhL1FUW (ORCPT ); Tue, 28 Dec 2021 00:20:22 -0500 Received: from mail-oi1-x230.google.com (mail-oi1-x230.google.com [IPv6:2607:f8b0:4864:20::230]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4F09FC06175B for ; Mon, 27 Dec 2021 21:20:22 -0800 (PST) Received: by mail-oi1-x230.google.com with SMTP id x10so23499108oix.6 for ; Mon, 27 Dec 2021 21:20:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RdZ0UWK+juD5hIJv/N6wqF64M3MWs7cXhgw6dZ2me2c=; b=gecW0ToB+ezNfgZBtqEGM4NktSYAlSPUX12ativA3a1GA5DK5dSZfmjRlt33U4Aa6a WEhhU5CLblKS1+CA7ZERcRbWGR8uuq0J9MdUvdmPk8lDjaX7Tr8riaDJzT8gbP619IM2 oqOORkabcQNMmloWNFDu+Opw0FwmA5CfNnTMhR9Juk4CRYDoRUDgv/mBBdd/M6vIf6cA vu+RbHLcaOtC33vXw3Z5D/vbN4wdtsgO1apBSbGgl74CtB9WbIPBxTStyhXfRl7roQhl IlDvaII5hZedcWXc0C2EAN/880yGAHj4uDi37gik9ud5QNNpPNsigSK/Gay5n2uKlaDv GqWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RdZ0UWK+juD5hIJv/N6wqF64M3MWs7cXhgw6dZ2me2c=; b=v2Z1zVxuB2Tj9fNUhPBqhDNfTPmRyRdn1vQ6V6eTpmG0WJX3XdLyrRBjpb1LpSmLPk pZ9yJT4NbWSPuwz8mVfpg8oJsnWw0VzsSm3izRd3gHf66x/xTS/zUngCN+1BYa9ZyCTE AHig6bKETSX3lbcrCtvOLajG4etRvI3s5QF6MjLD0GSNsl1rRWHXIpoB8KpFmagiTgmN UZQ1HL2g8pnTSSGEZLGyFMQIwAaWmdXPlEyaqRtnNKYCTX/dKL1uNSkR8fsD4Q437T23 jHo6m0Po+dgxB+Eb0jPq5Y42QOJpbvbJ6vgNpCTfyO6Pvy9dFOcAetlYIjU/x+AQ2Qyo fopQ== X-Gm-Message-State: AOAM530YIiHVnlgRZs7pCyF33FQspRnY+hfHaMQHiRrjTxRpEnoQ8X2V CjOdAsgscGRSlDYcPm+aa9j1gp+BOWA4zg== X-Google-Smtp-Source: ABdhPJxim6zcGg4oNp9c2nvgeHmzM4DmH7CrApzhOpfm+rBwgGbY1Q7Du7weKKBE0bh5D7NhZ28a8w== X-Received: by 2002:aca:6c5:: with SMTP id 188mr15108644oig.117.1640668821679; Mon, 27 Dec 2021 21:20:21 -0800 (PST) Received: from ripper.. (104-57-184-186.lightspeed.austtx.sbcglobal.net. [104.57.184.186]) by smtp.gmail.com with ESMTPSA id j5sm3002277oou.23.2021.12.27.21.20.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Dec 2021 21:20:21 -0800 (PST) From: Bjorn Andersson To: Kishon Vijay Abraham I , Vinod Koul , Rob Herring , Greg Kroah-Hartman , Heikki Krogerus , Hans de Goede Cc: "Rafael J. Wysocki" , linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Subject: [PATCH 6/8] typec: mux: Allow multiple mux_devs per mux Date: Mon, 27 Dec 2021 21:21:14 -0800 Message-Id: <20211228052116.1748443-7-bjorn.andersson@linaro.org> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211228052116.1748443-1-bjorn.andersson@linaro.org> References: <20211228052116.1748443-1-bjorn.andersson@linaro.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In the Qualcomm platforms the USB/DP PHY handles muxing and orientation switching of the SuperSpeed lines, but the SBU lines needs to be connected and switched by external (to the SoC) hardware. It's therefor necessary to be able to have the TypeC controller operate multiple TypeC muxes and switches. Use the newly introduced indirection object to handle this, to avoid having to taint the TypeC controllers with knowledge about the downstream hardware configuration. The max number of devs per indirection is set to 3, based on the number of ports defined in the usb-c-connector binding. Signed-off-by: Bjorn Andersson --- drivers/usb/typec/mux.c | 124 +++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 26 deletions(-) diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index d0b42c297aca..adf3681cf22d 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -17,8 +17,11 @@ #include "class.h" #include "mux.h" +#define TYPEC_MUX_MAX_DEVS 3 + struct typec_switch { - struct typec_switch_dev *sw_dev; + struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS]; + unsigned int num_sw_devs; }; static int switch_fwnode_match(struct device *dev, const void *fwnode) @@ -67,25 +70,48 @@ static void *typec_switch_match(struct fwnode_handle *fwnode, const char *id, */ struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode) { - struct typec_switch_dev *sw_dev; + struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS]; struct typec_switch *sw; + int count; + int err; + int i; sw = kzalloc(sizeof(*sw), GFP_KERNEL); if (!sw) return ERR_PTR(-ENOMEM); - sw_dev = fwnode_connection_find_match(fwnode, "orientation-switch", NULL, - typec_switch_match); - if (IS_ERR_OR_NULL(sw_dev)) { + count = fwnode_connection_find_matches(fwnode, "orientation-switch", NULL, + typec_switch_match, + (void **)sw_devs, + ARRAY_SIZE(sw_devs)); + if (count <= 0) { kfree(sw); - return ERR_CAST(sw_dev); + return NULL; } - WARN_ON(!try_module_get(sw_dev->dev.parent->driver->owner)); + for (i = 0; i < count; i++) { + if (IS_ERR(sw_devs[i])) { + err = PTR_ERR(sw_devs[i]); + goto put_sw_devs; + } + } + + for (i = 0; i < count; i++) { + WARN_ON(!try_module_get(sw_devs[i]->dev.parent->driver->owner)); + sw->sw_devs[i] = sw_devs[i]; + } - sw->sw_dev = sw_dev; + sw->num_sw_devs = count; return sw; + +put_sw_devs: + for (i = 0; i < count; i++) { + if (!IS_ERR(sw_devs[i])) + put_device(&sw_devs[i]->dev); + } + + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(fwnode_typec_switch_get); @@ -98,14 +124,17 @@ EXPORT_SYMBOL_GPL(fwnode_typec_switch_get); void typec_switch_put(struct typec_switch *sw) { struct typec_switch_dev *sw_dev; + unsigned int i; if (IS_ERR_OR_NULL(sw)) return; - sw_dev = sw->sw_dev; + for (i = 0; i < sw->num_sw_devs; i++) { + sw_dev = sw->sw_devs[i]; - module_put(sw_dev->dev.parent->driver->owner); - put_device(&sw_dev->dev); + module_put(sw_dev->dev.parent->driver->owner); + put_device(&sw_dev->dev); + } kfree(sw); } EXPORT_SYMBOL_GPL(typec_switch_put); @@ -170,13 +199,21 @@ int typec_switch_set(struct typec_switch *sw, enum typec_orientation orientation) { struct typec_switch_dev *sw_dev; + unsigned int i; + int ret; if (IS_ERR_OR_NULL(sw)) return 0; - sw_dev = sw->sw_dev; + for (i = 0; i < sw->num_sw_devs; i++) { + sw_dev = sw->sw_devs[i]; + + ret = sw_dev->set(sw_dev, orientation); + if (ret) + return ret; + } - return sw_dev->set(sw_dev, orientation); + return 0; } EXPORT_SYMBOL_GPL(typec_switch_set); @@ -208,7 +245,8 @@ EXPORT_SYMBOL_GPL(typec_switch_get_drvdata); /* ------------------------------------------------------------------------- */ struct typec_mux { - struct typec_mux_dev *mux_dev; + struct typec_mux_dev *mux_devs[TYPEC_MUX_MAX_DEVS]; + unsigned int num_mux_devs; }; static int mux_fwnode_match(struct device *dev, const void *fwnode) @@ -291,25 +329,48 @@ static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode, const struct typec_altmode_desc *desc) { - struct typec_mux_dev *mux_dev; + struct typec_mux_dev *mux_devs[TYPEC_MUX_MAX_DEVS]; struct typec_mux *mux; + int count; + int err; + int i; mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) return ERR_PTR(-ENOMEM); - mux_dev = fwnode_connection_find_match(fwnode, "mode-switch", (void *)desc, - typec_mux_match); - if (IS_ERR_OR_NULL(mux_dev)) { + count = fwnode_connection_find_matches(fwnode, "mode-switch", + (void *)desc, typec_mux_match, + (void **)mux_devs, + ARRAY_SIZE(mux_devs)); + if (count <= 0) { kfree(mux); - return ERR_CAST(mux_dev); + return NULL; } - WARN_ON(!try_module_get(mux_dev->dev.parent->driver->owner)); + for (i = 0; i < count; i++) { + if (IS_ERR(mux_devs[i])) { + err = PTR_ERR(mux_devs[i]); + goto put_mux_devs; + } + } + + for (i = 0; i < count; i++) { + WARN_ON(!try_module_get(mux_devs[i]->dev.parent->driver->owner)); + mux->mux_devs[i] = mux_devs[i]; + } - mux->mux_dev = mux_dev; + mux->num_mux_devs = count; return mux; + +put_mux_devs: + for (i = 0; i < count; i++) { + if (!IS_ERR(mux_devs[i])) + put_device(&mux_devs[i]->dev); + } + + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(fwnode_typec_mux_get); @@ -322,13 +383,16 @@ EXPORT_SYMBOL_GPL(fwnode_typec_mux_get); void typec_mux_put(struct typec_mux *mux) { struct typec_mux_dev *mux_dev; + unsigned int i; if (IS_ERR_OR_NULL(mux)) return; - mux_dev = mux->mux_dev; - module_put(mux_dev->dev.parent->driver->owner); - put_device(&mux_dev->dev); + for (i = 0; i < mux->num_mux_devs; i++) { + mux_dev = mux->mux_devs[i]; + module_put(mux_dev->dev.parent->driver->owner); + put_device(&mux_dev->dev); + } kfree(mux); } EXPORT_SYMBOL_GPL(typec_mux_put); @@ -336,13 +400,21 @@ EXPORT_SYMBOL_GPL(typec_mux_put); int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) { struct typec_mux_dev *mux_dev; + unsigned int i; + int ret; if (IS_ERR_OR_NULL(mux)) return 0; - mux_dev = mux->mux_dev; + for (i = 0; i < mux->num_mux_devs; i++) { + mux_dev = mux->mux_devs[i]; + + ret = mux_dev->set(mux_dev, state); + if (ret) + return ret; + } - return mux_dev->set(mux_dev, state); + return 0; } EXPORT_SYMBOL_GPL(typec_mux_set);