From patchwork Wed May 4 11:39:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laxman Dewangan X-Patchwork-Id: 618377 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3r0Gd01WtQz9ssM for ; Wed, 4 May 2016 21:52:52 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750868AbcEDLwb (ORCPT ); Wed, 4 May 2016 07:52:31 -0400 Received: from nat-hk.nvidia.com ([203.18.50.4]:38655 "EHLO hkmmgate102.nvidia.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752738AbcEDLwa (ORCPT ); Wed, 4 May 2016 07:52:30 -0400 Received: from hkpgpgate102.nvidia.com (Not Verified[10.18.92.9]) by hkmmgate102.nvidia.com id ; Wed, 04 May 2016 19:52:42 +0800 Received: from HKMAIL104.nvidia.com ([10.18.67.137]) by hkpgpgate102.nvidia.com (PGP Universal service); Wed, 04 May 2016 04:52:27 -0700 X-PGP-Universal: processed; by hkpgpgate102.nvidia.com on Wed, 04 May 2016 04:52:27 -0700 Received: from DRBGMAIL104.nvidia.com (10.18.16.23) by HKMAIL104.nvidia.com (10.18.16.13) with Microsoft SMTP Server (TLS) id 15.0.1130.7; Wed, 4 May 2016 11:52:26 +0000 Received: from HQMAIL103.nvidia.com (172.20.187.11) by DRBGMAIL104.nvidia.com (10.18.16.23) with Microsoft SMTP Server (TLS) id 15.0.1130.7; Wed, 4 May 2016 11:52:17 +0000 Received: from ldewanganubuntu-System-Product-Name.nvidia.com (172.20.13.39) by HQMAIL103.nvidia.com (172.20.187.11) with Microsoft SMTP Server id 15.0.1130.7 via Frontend Transport; Wed, 4 May 2016 11:52:13 +0000 From: Laxman Dewangan To: , , , CC: , , , , "Laxman Dewangan" Subject: [PATCH V3 4/4] soc/tegra: pmc: Register PMC child devices as platform device Date: Wed, 4 May 2016 17:09:33 +0530 Message-ID: <1462361973-27990-5-git-send-email-ldewangan@nvidia.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1462361973-27990-1-git-send-email-ldewangan@nvidia.com> References: <1462361973-27990-1-git-send-email-ldewangan@nvidia.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Power Management Controller(PMC) of Tegra does the multiple chip power related functionality for internal and IO interfacing. Some of the functionalities are power gating of IP blocks, IO pads voltage and power state configuration, system power state configurations, wakeup controls etc. Different functionalities of the PMC are provided through different framework like IO pads control can be provided through pinctrl framework, IO power control is via misc driver etc. All sub functionalities are represented as PMC child devices. Register the PMC child devices as platform device and fill the child devices table for Tegra124 and Tegra210. Signed-off-by: Laxman Dewangan --- Changes from V1: Reworked on DT for having flat entry and register all child devices as simple platform device instead of of_populate_device(). Changes from V2: - Handling of the release of child devices on error. - Register sub devices for T124 and T210 as T124 supports the DPD of IO pads. --- drivers/soc/tegra/pmc.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 0611cea..0eb652f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -132,6 +132,8 @@ struct tegra_pmc_soc { const u8 *cpu_powergates; const struct tegra_io_pads_control *io_pads_control; unsigned int num_io_pads; + const char **sub_devs_name; + unsigned int num_sub_devs; bool has_tsense_reset; bool has_gpu_clamps; }; @@ -158,6 +160,7 @@ struct tegra_pmc_soc { * @lp0_vec_size: size of the LP0 warm boot code * @powergates_available: Bitmap of available power gates * @powergates_lock: mutex for power gate register access + * @pdevs: Platform device for PMC child devices. */ struct tegra_pmc { struct device *dev; @@ -184,6 +187,8 @@ struct tegra_pmc { DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); struct mutex powergates_lock; + + struct platform_device **pdevs; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1310,6 +1315,57 @@ out: of_node_put(np); } +static int tegra_pmc_init_sub_devs(struct tegra_pmc *pmc) +{ + int ret, i; + + if (!pmc->soc->num_sub_devs) + return 0; + + pmc->pdevs = devm_kzalloc(pmc->dev, pmc->soc->num_sub_devs * + sizeof(**pmc->pdevs), GFP_KERNEL); + if (!pmc->pdevs) + return -ENOMEM; + + for (i = 0; i < pmc->soc->num_sub_devs; ++i) { + pmc->pdevs[i] = platform_device_register_data(pmc->dev, + pmc->soc->sub_devs_name[i], + 0, NULL, 0); + if (IS_ERR(pmc->pdevs[i])) { + ret = PTR_ERR(pmc->pdevs[i]); + dev_err(pmc->dev, + "Failed to register platform device for %s: %d\n", + pmc->soc->sub_devs_name[i], ret); + goto pdev_cleanups; + } + } + + return 0; + +pdev_cleanups: + while (--i >= 0) { + platform_device_unregister(pmc->pdevs[i]); + pmc->pdevs[i] = NULL; + } + + return ret; +} + +static void tegra_pmc_deinit_sub_devs(struct tegra_pmc *pmc) +{ + int i; + + if (!pmc->soc->num_sub_devs || !pmc->pdevs) + return; + + for (i = 0; i < pmc->soc->num_sub_devs; ++i) { + if (pmc->pdevs[i]) { + platform_device_unregister(pmc->pdevs[i]); + pmc->pdevs[i] = NULL; + } + } +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -1339,10 +1395,14 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_init_tsense_reset(pmc); + err = tegra_pmc_init_sub_devs(pmc); + if (err < 0) + dev_warn(pmc->dev, "Failed to register sub devices: %d\n", err); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) - return err; + goto cleanups; } err = register_restart_handler(&tegra_pmc_restart_handler); @@ -1350,7 +1410,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) debugfs_remove(pmc->debugfs); dev_err(&pdev->dev, "unable to register restart handler, %d\n", err); - return err; + goto cleanups; } tegra_powergate_init(pmc); @@ -1361,6 +1421,11 @@ static int tegra_pmc_probe(struct platform_device *pdev) mutex_unlock(&pmc->powergates_lock); return 0; + +cleanups: + tegra_pmc_deinit_sub_devs(pmc); + + return err; } #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) @@ -1544,6 +1609,10 @@ struct tegra_io_pads_control tegra124_io_pads_control[] = { TEGRA_IO_PADS_CONTROL(SYS_DDC, 58, -1), }; +static const char *tegra124_sub_devs_name[] = { + "pinctrl-tegra124-io-pad", +}; + static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra124_powergates), .powergates = tegra124_powergates, @@ -1551,6 +1620,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .cpu_powergates = tegra124_cpu_powergates, .io_pads_control = tegra124_io_pads_control, .num_io_pads = ARRAY_SIZE(tegra124_io_pads_control), + .sub_devs_name = tegra124_sub_devs_name, + .num_sub_devs = ARRAY_SIZE(tegra124_sub_devs_name), .has_tsense_reset = true, .has_gpu_clamps = true, }; @@ -1628,6 +1699,11 @@ struct tegra_io_pads_control tegra210_io_pads_control[] = { TEGRA_IO_PADS_CONTROL(LVDS, 57, -1), TEGRA_IO_PADS_CONTROL(AUDIO_HV, 61, 18), }; + +static const char *tegra210_sub_devs_name[] = { + "pinctrl-tegra210-io-pad", +}; + static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra210_powergates), .powergates = tegra210_powergates, @@ -1635,6 +1711,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .cpu_powergates = tegra210_cpu_powergates, .io_pads_control = tegra210_io_pads_control, .num_io_pads = ARRAY_SIZE(tegra210_io_pads_control), + .sub_devs_name = tegra210_sub_devs_name, + .num_sub_devs = ARRAY_SIZE(tegra210_sub_devs_name), .has_tsense_reset = true, .has_gpu_clamps = true, };