From patchwork Mon Dec 9 15:08:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Heikki Krogerus X-Patchwork-Id: 3311571 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 95ABBC0D4A for ; Mon, 9 Dec 2013 15:12:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 65C2F20268 for ; Mon, 9 Dec 2013 15:12:31 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F25A72016C for ; Mon, 9 Dec 2013 15:12:29 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vq2U2-0000wK-Vh; Mon, 09 Dec 2013 15:10:55 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vq2Tf-0007ll-Ux; Mon, 09 Dec 2013 15:10:31 +0000 Received: from mga14.intel.com ([143.182.124.37]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vq2T0-0007fv-La for linux-arm-kernel@lists.infradead.org; Mon, 09 Dec 2013 15:09:55 +0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by azsmga102.ch.intel.com with ESMTP; 09 Dec 2013 07:09:06 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.93,858,1378882800"; d="scan'208";a="441039601" Received: from blue.fi.intel.com ([10.237.72.156]) by fmsmga001.fm.intel.com with ESMTP; 09 Dec 2013 07:09:04 -0800 From: Heikki Krogerus To: Kishon Vijay Abraham I Subject: [PATCH 3/5] phy: improved lookup method Date: Mon, 9 Dec 2013 17:08:55 +0200 Message-Id: <1386601737-8735-4-git-send-email-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 1.8.5.1 In-Reply-To: <1386601737-8735-1-git-send-email-heikki.krogerus@linux.intel.com> References: <1386601737-8735-1-git-send-email-heikki.krogerus@linux.intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131209_100951_046239_494E6FA2 X-CRM114-Status: GOOD ( 20.76 ) X-Spam-Score: -6.9 (------) Cc: linux-samsung-soc@vger.kernel.org, linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Removes the need for the phys to be aware of their users even when not using DT. The method is copied from gpiolib.c. Signed-off-by: Heikki Krogerus --- drivers/phy/phy-core.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/phy/phy.h | 48 ++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 99dc046..05792d0 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -25,6 +25,7 @@ static struct class *phy_class; static DEFINE_MUTEX(phy_provider_mutex); static LIST_HEAD(phy_provider_list); +static LIST_HEAD(phy_lookup_list); static DEFINE_IDA(phy_ida); static void devm_phy_release(struct device *dev, void *res) @@ -85,6 +86,94 @@ static struct phy *phy_lookup(struct device *device, const char *con_id, return ERR_PTR(-ENODEV); } +/** + * phy_add_table() - register PHY/device association to the lookup list + * @table: association to register + */ +void phy_add_lookup_table(struct phy_lookup_table *table) +{ + mutex_lock(&phy_provider_mutex); + list_add_tail(&table->list, &phy_lookup_list); + mutex_unlock(&phy_provider_mutex); +} + +/** + * phy_add_table() - remove PHY/device association from the lookup list + * @table: association to be removed + */ +void phy_del_lookup_table(struct phy_lookup_table *table) +{ + mutex_lock(&phy_provider_mutex); + list_del(&table->list); + mutex_unlock(&phy_provider_mutex); +} + +static struct phy *find_phy_by_name(const char *name) +{ + struct class_dev_iter iter; + struct phy *phy = NULL; + struct device *dev; + + class_dev_iter_init(&iter, phy_class, NULL, NULL); + while ((dev = class_dev_iter_next(&iter))) { + if (!strcmp(dev_name(dev), name)) { + phy = to_phy(dev); + break; + } + } + class_dev_iter_exit(&iter); + + return phy; +} + +static struct phy_lookup_table *phy_get_lookup_table(struct device *dev) +{ + const char *dev_id = dev ? dev_name(dev) : NULL; + struct phy_lookup_table *table; + + mutex_lock(&phy_provider_mutex); + list_for_each_entry(table, &phy_lookup_list, list) + if (!strcmp(table->dev_id, dev_id)) + goto out; + table = NULL; +out: + mutex_unlock(&phy_provider_mutex); + return table; +} + +static struct phy *phy_find(struct device *dev, const char *con_id, + unsigned int idx) +{ + struct phy_lookup_table *table; + struct phy_lookup *p; + struct phy *phy; + + table = phy_get_lookup_table(dev); + if (!table) + /* fall-back to the old lookup method for now */ + return phy_lookup(dev, con_id, idx); + + for (p = &table->table[0]; p->phy_name; p++) { + /* index must always match exactly */ + if (idx != p->idx) + continue; + + /* If the lookup entry has a con_id, require exact match */ + if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) + continue; + + phy = find_phy_by_name(p->phy_name); + if (!phy) { + dev_warn(dev, "no PHY by the name %s\n", p->phy_name); + return ERR_PTR(-ENODEV); + } + + return phy; + } + + return ERR_PTR(-ENODEV); +} + static struct phy_provider *of_phy_provider_lookup(struct device_node *node) { struct phy_provider *phy_provider; @@ -386,7 +475,7 @@ struct phy *phy_get_index(struct device *dev, const char *con_id, */ if (!phy || IS_ERR(phy)) { dev_dbg(dev, "using lookup tables for PHY lookup"); - phy = phy_lookup(dev, con_id, idx); + phy = phy_find(dev, con_id, idx); } if (IS_ERR(phy)) { diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 43d1a23..cca363a 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -98,6 +98,54 @@ struct phy_init_data { .port = _port, \ } +/** + * struct phy_lookup - Lookup entry for associating PHYs + * @phy_name: device name of the PHY + * @con_id: name of the PHY from device's point of view + * @idx: index of the PHY when name is not used + */ +struct phy_lookup { + const char *phy_name; + const char *con_id; + unsigned int idx; +}; + +/** + * struct phy_lookup_table - association of PHYs to specific device + * @list: entry in the lookup list + * @dev_id: the name of the device + * @table: table of PHYs attached to this device + */ +struct phy_lookup_table { + struct list_head list; + const char *dev_id; + struct phy_lookup table[]; +}; + +/** + * Simple definition of a single PHY under a consumer + */ +#define PHY_LOOKUP(_phy_name, _con_id) \ +{ \ + PHY_LOOKUP_IDX(_phy_name, _con_id, 0), \ + { }, \ +} + +/** + * Use this macro if you need to have several PHYs under the same con_id. + * Each PHY needs to use a different index and can be accessed using + * phy_get_index() + */ +#define PHY_LOOKUP_IDX(_phy_name, _con_id, _idx) \ +{ \ + .phy_name = _phy_name, \ + .con_id = _con_id, \ + .idx = _idx, \ +} + +void phy_add_lookup_table(struct phy_lookup_table *); +void phy_del_lookup_table(struct phy_lookup_table *); + #define to_phy(dev) (container_of((dev), struct phy, dev)) #define of_phy_provider_register(dev, xlate) \