Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp12124317ybl; Sat, 28 Dec 2019 05:46:30 -0800 (PST) X-Google-Smtp-Source: APXvYqydR2JiQXsz/vjCg049oUis2LCQUEgnJ4auKOfWZkeHX09JJI5FSOSuhIJ8maGQuAQOr0ku X-Received: by 2002:a9d:4e97:: with SMTP id v23mr59302594otk.201.1577540790498; Sat, 28 Dec 2019 05:46:30 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1577540790; cv=pass; d=google.com; s=arc-20160816; b=THw7R/AlBFb4UPt1u+2kITRCRsQPE+smH4a/6H3CWf4dtqzqHoWV3QmRqOVNnKUY9i IBv08RK2Ui4lmYHyMm6F/sJvD+SkgEPzet1ENQL23FtMfGaeCxTeY2+rUf9nI7qZxWLy h+6HKFbC525srNZSsGuw2j/3sDqDJf9iFUuJvy+QojgUNHl8bGKR7qiS1wD8QaSAOPCR da8oCSle3aT5sidREEFZmjG2kjERPYVAuEQrmo5K1EiyvdyHcKmcBylquozUmXNYNqeA wDgQs7VzbsMtClpwmKa75l4Ntx2NEZ7gMHOBC4ikqqDV2cjnUkN/9x27bQwJWwDL+47T YjBw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:mime-version:references:in-reply-to :message-id:date:subject:cc:from:dkim-signature; bh=uflWicBJl2zVSUsLFobexwqvaENoSf5jWFPvcn+N2qs=; b=hnOs3xBSufem0VKKnX8fSU+23+Cvi2SWIvGtvAa2OT2BDgZP+QFoNgI/K18XfZhH/N kRmsrGYGGz/M/5gaioqa1i+JtRyYe3h0TvCdZgOoVyOuarLTJ3mBlPDs1s6dtsmZUJMR WOisxE/o9XBGRX0+07fltFSUuUehDjb4JQ26mpU/sXVf03Np6uLx93c670cZj8LuXGSk KsCC571KTMI5AtcV95hJejuHNcnJ2ZEY8ulPDdiH7QuQ8YiLvpObGX2Svp/X7DHRdYEo 2W0OzxVRNg/QY4ZNopB5+gpAVo96ecyRrc6B73UwQpGd8boxH1x6ZaPsjvzaspe72DVW wu/w== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@amdcloud.onmicrosoft.com header.s=selector2-amdcloud-onmicrosoft-com header.b=BX8o8KH5; arc=pass (i=1); spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w18si21130615otl.54.2019.12.28.05.46.19; Sat, 28 Dec 2019 05:46:30 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@amdcloud.onmicrosoft.com header.s=selector2-amdcloud-onmicrosoft-com header.b=BX8o8KH5; arc=pass (i=1); spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726465AbfL1NnV (ORCPT + 99 others); Sat, 28 Dec 2019 08:43:21 -0500 Received: from mail-dm6nam11on2072.outbound.protection.outlook.com ([40.107.223.72]:27745 "EHLO NAM11-DM6-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726080AbfL1NnV (ORCPT ); Sat, 28 Dec 2019 08:43:21 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VezUTt9iBkaxIwTMmACh3BIgotRUWLNE4RqRr+aQDFdgzM7FH0mhcULyqPrnKhVX+Sc19Q8Mv6E+0QWO+IlJDCviZD3lqv2qv85at1wahoU0jycf/E9TampDAkDApuiKCnfgAKe4vyf+DS0HH0WvW4DUCUYIeHfzHCGqJQ0uhG32Nybim/K7G87IoY6J+cUirR5/OPN2UuJIol/ZEHvcITgnavXTgKhy+CX++oHl2W1Cbwo5m3dbtftC1CZx3PvqPz2c54vyaOFRC9FrXzJ57R93xjXe0wCj1xzkPjS9xODWcdP8h5cHvWsUmegic6L8dUBt940pJ+txqJcKuZHATQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=uflWicBJl2zVSUsLFobexwqvaENoSf5jWFPvcn+N2qs=; b=SZ3e+onWtFqfpW8pJw7O2pnxtes4c7fcc37ZlAq4buRVwwtUOFESnyr5oSnCG55xogt4nJOiDGQ1NmxAGBzpMu2FjfqOwBC0lilF+XAk56KiPi+hi2bX5BQ+Ls19ZVfbu2NfZA5fM0YL17Xyo3oG7Cs6i/iArepiMOvNQbUOrhuzB+AiC7iwb28+pruCiu4P1yI9h1ZP4D4wuH/8qo+9JuyOS2WHtXZuIhZw3fBeRpKJFUOGfutwHfHqcqGjp5aLCm2mhyPab7axo/+IHH+1jBv0jF5DdOhhZvn/52h8hYezumQGw6FsGLGRyy1qdhdh6I7/W0QfkRxGj42BLrk66g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none (sender ip is 165.204.84.17) smtp.rcpttodomain=google.com smtp.mailfrom=amd.com; dmarc=permerror action=none header.from=amd.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector2-amdcloud-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=uflWicBJl2zVSUsLFobexwqvaENoSf5jWFPvcn+N2qs=; b=BX8o8KH5z/UeSiOhAGXI3xOG/iMw4l1B1unSaiE9PToNBWucSUr+d6/nY3/UfubQryfBthvqNMvIsYTQ8HGYxczaLZJ7KqLPQT3/+CAXTkrDCQJR4b5AwS1f3QKZkIckD2w3UI7oarRaeIJX7fwEUxzF/LXclOV2FLy8DE5f3fE= Received: from DM3PR12CA0073.namprd12.prod.outlook.com (2603:10b6:0:57::17) by MN2PR12MB3598.namprd12.prod.outlook.com (2603:10b6:208:d1::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2581.11; Sat, 28 Dec 2019 13:43:13 +0000 Received: from DM6NAM11FT037.eop-nam11.prod.protection.outlook.com (2a01:111:f400:7eaa::202) by DM3PR12CA0073.outlook.office365.com (2603:10b6:0:57::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2581.11 via Frontend Transport; Sat, 28 Dec 2019 13:43:13 +0000 Authentication-Results: spf=none (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; google.com; dkim=none (message not signed) header.d=none;google.com; dmarc=permerror action=none header.from=amd.com; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) Received: from SATLEXMB01.amd.com (165.204.84.17) by DM6NAM11FT037.mail.protection.outlook.com (10.13.172.122) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.2581.11 via Frontend Transport; Sat, 28 Dec 2019 13:43:13 +0000 Received: from SATLEXMB04.amd.com (10.181.40.145) by SATLEXMB01.amd.com (10.181.40.142) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Sat, 28 Dec 2019 07:43:12 -0600 Received: from SATLEXMB02.amd.com (10.181.40.143) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Sat, 28 Dec 2019 07:43:12 -0600 Received: from vishnu-All-Series.amd.com (10.180.168.240) by SATLEXMB02.amd.com (10.181.40.143) with Microsoft SMTP Server id 15.1.1713.5 via Frontend Transport; Sat, 28 Dec 2019 07:43:08 -0600 From: Ravulapati Vishnu vardhan rao CC: , , , Ravulapati Vishnu vardhan rao , "Liam Girdwood" , Jaroslav Kysela , "Takashi Iwai" , Vijendar Mukunda , Kuninori Morimoto , Colin Ian King , YueHaibing , Dan Carpenter , "moderated list:SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEM..." , open list Subject: [PATCH 5/6] ASoC: amd: Added ACP3x system resume and runtime pm Date: Sat, 28 Dec 2019 19:10:59 +0530 Message-ID: <1577540460-21438-6-git-send-email-Vishnuvardhanrao.Ravulapati@amd.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1577540460-21438-1-git-send-email-Vishnuvardhanrao.Ravulapati@amd.com> References: <1577540460-21438-1-git-send-email-Vishnuvardhanrao.Ravulapati@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:165.204.84.17;IPV:;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(4636009)(396003)(136003)(39860400002)(346002)(376002)(428003)(199004)(189003)(23433003)(26005)(478600001)(7416002)(8936002)(109986005)(2616005)(426003)(7696005)(336012)(8676002)(81156014)(81166006)(36756003)(2906002)(186003)(4326008)(6666004)(70586007)(356004)(5660300002)(54906003)(316002)(30864003)(70206006)(86362001)(266003)(32563001);DIR:OUT;SFP:1101;SCL:1;SRVR:MN2PR12MB3598;H:SATLEXMB01.amd.com;FPR:;SPF:None;LANG:en;PTR:InfoDomainNonexistent;A:1;MX:1; X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 9ad69751-7dd4-4334-4c1f-08d78b9be272 X-MS-TrafficTypeDiagnostic: MN2PR12MB3598:|MN2PR12MB3598: X-Microsoft-Antispam-PRVS: X-MS-Exchange-Transport-Forked: True X-MS-Oob-TLC-OOBClassifiers: OLM:21; X-Forefront-PRVS: 02652BD10A X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: OU2s2mO8p54pY4rkgNHhed/hCVckSwcsWRxv6wgdAbVTMgmLz6XmeecOmfaVUBwloR7v5hejwqlpBT8/nB2m68F9XgYJHwkFhbvgXpMlmXdMef+UVjSfZ7c8buUJ2OMh8lqbX4cHwAYpuIwSYv5aXZ/QskGBMU1OGBd92q1BjPmCWxFvexFYBYawJdpKufcrTVryIghUiyUD/82ioylf7jJgjyMl2pC2jz5bJLArUubEx48wopWRvXbh5XhOW4jPDFWCGM5pMpxFFGPUAEYzaNVkBFpMxARytfsoza6SJYc0OwKqpuJuNRm/ngQbBiajwI60+vBEyIOg4WkpcPLvy7N77z8tp6FJD2MlIeP9ci4c892d4bzbJv8FaNYxoOPExvb1plGAA2ThIs9dNVPyER7KBA4/I092Zgl9jbxhmhmuiV2P5+PcWeUL7p2EYc0CWoTfK1EOElkhJr1FmAqNKZFjgqUhKVh7VpqXJ5d8XcwoIG9vAX7rIsu1Psd/JaAX/bRATSLQ9EPtAVrN/TueFzmr/IgoviVB4DUeOW1kdN0= X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Dec 2019 13:43:13.0687 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 9ad69751-7dd4-4334-4c1f-08d78b9be272 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB01.amd.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR12MB3598 To: unlisted-recipients:; (no To-header on input) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When system wide suspend happens, ACP will be powered off and when system resumes,for audio usecase to continue,all the runtime configuration data needs to be programmed again. Added resume pm call back to ACP pm ops and also added runtime PM operations for ACP3x PCM platform device. Device will enter into D3 state when there is no activity on audio I2S lines. Signed-off-by: Ravulapati Vishnu vardhan rao --- sound/soc/amd/raven/acp3x-pcm-dma.c | 149 ++----------------------------- sound/soc/amd/raven/acp3x.h | 7 ++ sound/soc/amd/raven/pci-acp3x.c | 173 ++++++++++++++++++++++++++++++++++-- 3 files changed, 180 insertions(+), 149 deletions(-) diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index c5d7f35..151daa9 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -57,106 +57,6 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = { .periods_max = CAPTURE_MAX_NUM_PERIODS, }; -static int acp3x_power_on(void __iomem *acp3x_base, bool on) -{ - u16 val, mask; - u32 timeout; - - if (on == true) { - val = 1; - mask = ACP3x_POWER_ON; - } else { - val = 0; - mask = ACP3x_POWER_OFF; - } - - rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL); - timeout = 0; - while (true) { - val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); - if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask) - break; - if (timeout > 100) { - pr_err("ACP3x power state change failure\n"); - return -ENODEV; - } - timeout++; - cpu_relax(); - } - return 0; -} - -static int acp3x_reset(void __iomem *acp3x_base) -{ - u32 val, timeout; - - rv_writel(1, acp3x_base + mmACP_SOFT_RESET); - timeout = 0; - while (true) { - val = rv_readl(acp3x_base + mmACP_SOFT_RESET); - if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) || - timeout > 100) { - if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) - break; - return -ENODEV; - } - timeout++; - cpu_relax(); - } - - rv_writel(0, acp3x_base + mmACP_SOFT_RESET); - timeout = 0; - while (true) { - val = rv_readl(acp3x_base + mmACP_SOFT_RESET); - if (!val || timeout > 100) { - if (!val) - break; - return -ENODEV; - } - timeout++; - cpu_relax(); - } - return 0; -} - -static int acp3x_init(void __iomem *acp3x_base) -{ - int ret; - - /* power on */ - ret = acp3x_power_on(acp3x_base, true); - if (ret) { - pr_err("ACP3x power on failed\n"); - return ret; - } - /* Reset */ - ret = acp3x_reset(acp3x_base); - if (ret) { - pr_err("ACP3x reset failed\n"); - return ret; - } - return 0; -} - -static int acp3x_deinit(void __iomem *acp3x_base) -{ - int ret; - - /* Reset */ - ret = acp3x_reset(acp3x_base); - if (ret) { - pr_err("ACP3x reset failed\n"); - return ret; - } - /* power off */ - ret = acp3x_power_on(acp3x_base, false); - if (ret) { - pr_err("ACP3x power off failed\n"); - return ret; - } - return 0; -} - static irqreturn_t i2s_irq_handler(int irq, void *dev_id) { struct i2s_dev_data *rv_i2s_data; @@ -479,7 +379,7 @@ static int acp3x_audio_probe(struct platform_device *pdev) struct resource *res; struct i2s_dev_data *adata; unsigned int irqflags; - int status, ret; + int status; if (!pdev->dev.platform_data) { dev_err(&pdev->dev, "platform_data not retrieved\n"); @@ -511,53 +411,29 @@ static int acp3x_audio_probe(struct platform_device *pdev) adata->i2s_irq = res->start; dev_set_drvdata(&pdev->dev, adata); - /* Initialize ACP */ - status = acp3x_init(adata->acp3x_base); - if (status) - return -ENODEV; - status = devm_snd_soc_register_component(&pdev->dev, &acp3x_i2s_component, NULL, 0); if (status) { dev_err(&pdev->dev, "Fail to register acp i2s component\n"); - ret = -ENODEV; - goto dev_err; + return -ENODEV; } status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler, irqflags, "ACP3x_I2S_IRQ", adata); if (status) { dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n"); - ret = -ENODEV; - goto dev_err; + return -ENODEV; } - pm_runtime_set_autosuspend_delay(&pdev->dev, 5000); + pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); + pm_runtime_allow(&pdev->dev); return 0; - -dev_err: - status = acp3x_deinit(adata->acp3x_base); - if (status) - dev_err(&pdev->dev, "ACP de-init failed\n"); - else - dev_dbg(&pdev->dev, "ACP de-initialized\n"); - return ret; } static int acp3x_audio_remove(struct platform_device *pdev) { - struct i2s_dev_data *adata; - int ret; - - adata = dev_get_drvdata(&pdev->dev); - ret = acp3x_deinit(adata->acp3x_base); - if (ret) - dev_err(&pdev->dev, "ACP de-init failed\n"); - else - dev_dbg(&pdev->dev, "ACP de-initialized\n"); - pm_runtime_disable(&pdev->dev); return 0; } @@ -565,15 +441,11 @@ static int acp3x_audio_remove(struct platform_device *pdev) static int acp3x_resume(struct device *dev) { struct i2s_dev_data *adata; - int status; u32 val, reg_val, frmt_val; reg_val = 0; frmt_val = 0; adata = dev_get_drvdata(dev); - status = acp3x_init(adata->acp3x_base); - if (status) - return -ENODEV; if (adata->play_stream && adata->play_stream->runtime) { struct i2s_stream_instance *rtd = @@ -620,14 +492,8 @@ static int acp3x_resume(struct device *dev) static int acp3x_pcm_runtime_suspend(struct device *dev) { struct i2s_dev_data *adata; - int status; adata = dev_get_drvdata(dev); - status = acp3x_deinit(adata->acp3x_base); - if (status) - dev_err(dev, "ACP de-init failed\n"); - else - dev_dbg(dev, "ACP de-initialized\n"); rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); @@ -637,12 +503,9 @@ static int acp3x_pcm_runtime_suspend(struct device *dev) static int acp3x_pcm_runtime_resume(struct device *dev) { struct i2s_dev_data *adata; - int status; adata = dev_get_drvdata(dev); - status = acp3x_init(adata->acp3x_base); - if (status) - return -ENODEV; + rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB); return 0; } diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h index 43213ae..b6a80dc 100644 --- a/sound/soc/amd/raven/acp3x.h +++ b/sound/soc/amd/raven/acp3x.h @@ -68,6 +68,13 @@ #define SLOT_WIDTH_16 0x10 #define SLOT_WIDTH_24 0x18 #define SLOT_WIDTH_32 0x20 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 +#define ACP_PGFSM_STATUS_MASK 0x03 +#define ACP_POWERED_ON 0x00 +#define ACP_POWER_ON_IN_PROGRESS 0x01 +#define ACP_POWERED_OFF 0x02 +#define ACP_POWER_OFF_IN_PROGRESS 0x03 struct acp3x_platform_info { u16 play_i2s_instance; diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c index 94f5f21..2f9f5290 100644 --- a/sound/soc/amd/raven/pci-acp3x.c +++ b/sound/soc/amd/raven/pci-acp3x.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "acp3x.h" @@ -19,6 +21,109 @@ struct acp3x_dev_data { struct platform_device *pdev[ACP3x_DEVS]; }; +static int acp3x_power_on(void __iomem *acp3x_base) +{ + u32 val; + int timeout; + + val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); + + if (val == 0) + return val; + + if (!((val & ACP_PGFSM_STATUS_MASK) == + ACP_POWER_ON_IN_PROGRESS)) + rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, + acp3x_base + mmACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); + if (!val) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int acp3x_power_off(void __iomem *acp3x_base) +{ + u32 val; + int timeout; + + rv_writel(ACP_PGFSM_CNTL_POWER_OFF_MASK, + acp3x_base + mmACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS); + if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int acp3x_reset(void __iomem *acp3x_base) +{ + u32 val; + int timeout; + + rv_writel(1, acp3x_base + mmACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_SOFT_RESET); + if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) + break; + cpu_relax(); + } + rv_writel(0, acp3x_base + mmACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rv_readl(acp3x_base + mmACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static int acp3x_init(void __iomem *acp3x_base) +{ + int ret; + + /* power on */ + ret = acp3x_power_on(acp3x_base); + if (ret) { + pr_err("ACP3x power on failed\n"); + return ret; + } + /* Reset */ + ret = acp3x_reset(acp3x_base); + if (ret) { + pr_err("ACP3x reset failed\n"); + return ret; + } + return 0; +} + +static int acp3x_deinit(void __iomem *acp3x_base) +{ + int ret; + + /* Reset */ + ret = acp3x_reset(acp3x_base); + if (ret) { + pr_err("ACP3x reset failed\n"); + return ret; + } + /* power off */ + ret = acp3x_power_off(acp3x_base); + if (ret) { + pr_err("ACP3x power off failed\n"); + return ret; + } + return 0; +} + static int snd_acp3x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -64,6 +169,9 @@ static int snd_acp3x_probe(struct pci_dev *pci, } pci_set_master(pci); pci_set_drvdata(pci, adata); + ret = acp3x_init(adata->acp3x_base); + if (ret) + goto disable_msi; val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG); switch (val) { @@ -73,7 +181,7 @@ static int snd_acp3x_probe(struct pci_dev *pci, GFP_KERNEL); if (!adata->res) { ret = -ENOMEM; - goto disable_msi; + goto de_init; } adata->res[0].name = "acp3x_i2s_iomem"; @@ -118,7 +226,7 @@ static int snd_acp3x_probe(struct pci_dev *pci, pdevinfo[2].parent = &pci->dev; pdevinfo[2].num_res = 1; pdevinfo[2].res = &adata->res[2]; - for (i = 0; i < ACP3x_DEVS ; i++) { + for (i = 0; i < ACP3x_DEVS; i++) { adata->pdev[i] = platform_device_register_full(&pdevinfo[i]); if (IS_ERR(adata->pdev[i])) { @@ -134,12 +242,21 @@ static int snd_acp3x_probe(struct pci_dev *pci, ret = -ENODEV; goto disable_msi; } + pm_runtime_set_autosuspend_delay(&pci->dev, 2000); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_set_active(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_enable(&pci->dev); + pm_runtime_allow(&pci->dev); return 0; unregister_devs: if (val == I2S_MODE) - for (i = 0 ; i < ACP3x_DEVS ; i++) + for (i = 0; i < ACP3x_DEVS; i++) platform_device_unregister(adata->pdev[i]); +de_init: + if (acp3x_deinit(adata->acp3x_base)) + dev_err(&pci->dev, "ACP de-init failed\n"); disable_msi: pci_disable_msi(pci); release_regions: @@ -150,15 +267,56 @@ static int snd_acp3x_probe(struct pci_dev *pci, return ret; } +static int snd_acp3x_suspend(struct device *dev) +{ + int ret; + struct acp3x_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = acp3x_deinit(adata->acp3x_base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + else + dev_dbg(dev, "ACP de-initialized\n"); + + return 0; +} + +static int snd_acp3x_resume(struct device *dev) +{ + int ret; + struct acp3x_dev_data *adata; + + adata = dev_get_drvdata(dev); + ret = acp3x_init(adata->acp3x_base); + if (ret) { + dev_err(dev, "ACP init failed\n"); + return ret; + } + return 0; +} + +static const struct dev_pm_ops acp3x_pm = { + .runtime_suspend = snd_acp3x_suspend, + .runtime_resume = snd_acp3x_resume, + .resume = snd_acp3x_resume, +}; + static void snd_acp3x_remove(struct pci_dev *pci) { - struct acp3x_dev_data *adata = pci_get_drvdata(pci); - int i; + struct acp3x_dev_data *adata; + int i, ret; + adata = pci_get_drvdata(pci); if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) { - for (i = 0 ; i < ACP3x_DEVS ; i++) + for (i = 0; i < ACP3x_DEVS; i++) platform_device_unregister(adata->pdev[i]); } + ret = acp3x_deinit(adata->acp3x_base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_disable(&pci->dev); + pm_runtime_get_noresume(&pci->dev); pci_disable_msi(pci); pci_release_regions(pci); pci_disable_device(pci); @@ -177,6 +335,9 @@ static struct pci_driver acp3x_driver = { .id_table = snd_acp3x_ids, .probe = snd_acp3x_probe, .remove = snd_acp3x_remove, + .driver = { + .pm = &acp3x_pm, + } }; module_pci_driver(acp3x_driver); -- 2.7.4