From patchwork Mon Oct 26 08:43:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 7486321 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id BD4A49F36A for ; Mon, 26 Oct 2015 08:53:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6657A2047B for ; Mon, 26 Oct 2015 08:53:49 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 7CDCA20674 for ; Mon, 26 Oct 2015 08:53:47 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 5E19A261A83; Mon, 26 Oct 2015 09:53:46 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAD_ENC_HEADER,BAYES_00, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 28AB92606FE; Mon, 26 Oct 2015 09:47:55 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 5130D2651FD; Mon, 26 Oct 2015 09:47:54 +0100 (CET) Received: from relmlie3.idc.renesas.com (relmlor4.renesas.com [210.160.252.174]) by alsa0.perex.cz (Postfix) with ESMTP id 81AE12606E2 for ; Mon, 26 Oct 2015 09:44:02 +0100 (CET) Received: from unknown (HELO relmlir1.idc.renesas.com) ([10.200.68.151]) by relmlie3.idc.renesas.com with ESMTP; 26 Oct 2015 17:44:01 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir1.idc.renesas.com (Postfix) with ESMTP id 339B648E8D; Mon, 26 Oct 2015 17:44:01 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 1AAFE2806E; Mon, 26 Oct 2015 17:44:00 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id DDD1A2806D; Mon, 26 Oct 2015 17:44:00 +0900 (JST) Received: from relmlii2.idc.renesas.com [10.200.68.66] by relmlac2.idc.renesas.com with ESMTP id TAM20687; Mon, 26 Oct 2015 17:44:00 +0900 X-IronPort-AV: E=Sophos;i="5.20,200,1444662000"; d="scan'";a="198438300" Received: from mail-sg2apc01lp0240.outbound.protection.outlook.com (HELO APC01-SG2-obe.outbound.protection.outlook.com) ([65.55.88.240]) by relmlii2.idc.renesas.com with ESMTP/TLS/AES256-SHA; 26 Oct 2015 17:43:59 +0900 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=kuninori.morimoto.gx@renesas.com; Received: from morimoto-PC.renesas.com (211.11.155.144) by HKXPR06MB1014.apcprd06.prod.outlook.com (10.161.178.156) with Microsoft SMTP Server (TLS) id 15.1.306.13; Mon, 26 Oct 2015 08:43:57 +0000 Message-ID: <87bnbm3tyb.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto User-Agent: Wanderlust/2.15.9 Emacs/24.3 Mule/6.0 MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") To: Mark Brown In-Reply-To: <871tci58tc.wl%kuninori.morimoto.gx@renesas.com> References: <871tci58tc.wl%kuninori.morimoto.gx@renesas.com> Date: Mon, 26 Oct 2015 08:43:57 +0000 X-Originating-IP: [211.11.155.144] X-ClientProxiedBy: HK2PR02CA0017.apcprd02.prod.outlook.com (25.163.104.155) To HKXPR06MB1014.apcprd06.prod.outlook.com (25.161.178.156) X-Microsoft-Exchange-Diagnostics: 1; HKXPR06MB1014; 2:1s7tbI7Wg8zSWwbp1wcuprA5MDUBwtg9uacgMquq1qXzq70luZbq6B84YsKkHIqQe3/Z2MoJyPOj715+JHa3TYuSiT79tzklAPaHRGwHtN3qnM1WeOUQVRzyn5DB9Ioxyzjqz2kVaeXmPU5ku0JDlyKCYRpJTqbt3zFe6xeLv4s=; 3:xjB6MbCaqECbABX5muivTwre+epkcJ1/z85bpmjjxZfR/uwD4D4OnfJm2O3Wk4v4UC6ZTX98IetOZMOH7aRAulpxu+kJzdVYgo5l7I/Zdgl/wiiWG0uppf4ZOl4d3S+Q6FzvKqfl6aK/a1DKecFy+w==; 25:NJse5b8NXuvYBrHJiMDfJqx7m5ijyYHpC5RXpCwGh+jPIK65iRRK3toBGPJRI/8z/lHA8tTj8BlMcy016TSYQ3aZUBFOnLbcV3XL3pougqIn8Ufo8qYw5XPnFJ5TrqUJHmlrO1zgjBOZu0sayZlGaO/BYTGUIdrM68ZOrbqgCJCcs36TCjxYZBwJ+sx93xaffRgSgUHIMbTfQuaFea+uFpD/2dvwYKknkhtKgiCDEv9D5H9fDnzwj6tjN/Hzxk0TZ3FYp9MZkCqh18P7xh47Mg== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:HKXPR06MB1014; X-Microsoft-Exchange-Diagnostics: 1; HKXPR06MB1014; 20:MK3mRJ4JTtvSWYV++h5Ml/HrmEb6FnhvqKwYuP/9xACtC23vZXRTU7GSCXO2TFzUtz+qVw2Q5WkVdEcqZaxoy8HGOaT3KZwCm8QlMRUoBN3C/laaqE8gLjDv73vf+M2LMNo44FHUypRIgjkFbq63bdTmN+Lb6xWMeUVCN1lSfwi3U+RT/o/FsfMUsSV3Af03RbhKKwQeXF+p+KfXzk2J8YNRN8n49wDF8o2hbUl8MswXs/u1skaGhIsOJKnEbSJnac8OEtX8dF1WYvTAkevQGA71gUt4qYoWCrl/zDiFHzOycvMm7vIW4YORk3iiJu/xxmt/0YqfAOZqXXizzboS8ZJFduTNjmhdAgCyTmtlFaB1OF8zTsfpf1Wz+YeG+AAcDC4Gh7NLG27mImudIx67pO56EH+1mStwkh6fpeJHDzbA74KtCimdO8D7MVNxJC/2hB2TTw1k+4z5ZfVIe/7Ha6iPCoRavGdmTvTpVzr4bpzuJwl1e3oYwiOWgunWpX/v; 4:KrFbbitmbi+qptcUMVCry7TKxU9Q9ZpJ2ExQ14Awzdx6vLeVvNXEYcC0YNqi9kMN6YPQUr9k9iJmbS5XMvOzUuIruAPsPP1A6KPTqO+74TvUkg0ej25jVwPWXGbrEJNJoSrnscobrKBuADKNX+NPmKenvv0Srl7X44v7IY1auaC3sp4cSpEsK5/K9xjvoEsx8Yg2qK/yoJjxe4JglE0elWOjGfoYsp7tV+7g+nqbAAg2I+EbVWf9rXORbS5rMUSz7CegYtrBvYgvYlUjvOfePF6sHHm8rveqWRVdqqsxZ/lU2Enx7nYWUSw7vy+OLQTdAy8XFzPfUifyu0fOEQZx+zYHR7mOuQKnabLfLGNAKR1I1jLpPj95j/qAHvwRQMRk X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(85106069007906); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(520078)(8121501046)(3002001)(102215026); SRVR:HKXPR06MB1014; BCL:0; PCL:0; RULEID:; SRVR:HKXPR06MB1014; X-Forefront-PRVS: 0741C77572 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(189002)(199003)(76176999)(77096005)(66066001)(50986999)(122386002)(54356999)(101416001)(5004730100002)(5007970100001)(87976001)(19580395003)(47776003)(2950100001)(19580405001)(40100003)(83506001)(69596002)(23726002)(53416004)(42186005)(92566002)(106356001)(105586002)(229853001)(33646002)(86362001)(97736004)(110136002)(5008740100001)(4001350100001)(81156007)(5001960100002)(189998001)(5890100001)(36756003)(46406003)(50466002); DIR:OUT; SFP:1102; SCL:1; SRVR:HKXPR06MB1014; H:morimoto-PC.renesas.com; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HKXPR06MB1014; 23:cFCZk/JfZoExvaU2EoD2ueEIxTUoVCatLGgzgos2j?= =?us-ascii?Q?F/ZKPpDCUGkDockhakgo2UB5i7wiMjWgr/BzepUHjzNd9UccuFbn0RKLQZJU?= =?us-ascii?Q?LInn15NRStGJNXXxHmiiSTMtbmAraeIQJcHFQivV4GWyWalsFjOXCC8bgSG/?= =?us-ascii?Q?WQwK4Wl7dnzf2spiVN0YZRPK3RvOvVvIT3PtYtLqQJHvwkj8yni9jW+3fuFa?= =?us-ascii?Q?RBjToHDZ/gincnhzZhX7Bfa5eUvd3eM+nS5bWw4wZ2tVDIskKsRz8ixJd/Bk?= =?us-ascii?Q?IAkFYHdpeag0NUAYROvrFkCjrsyxxglOxX3xFuzSGsEBcsGckVQOIJpqJDMO?= =?us-ascii?Q?bW5Z+sgF4fJw9hRlqz1/uB/Hn4bXOZ4yot5uYimPB2ao5cPA54LenZJwWd7W?= =?us-ascii?Q?JVpoFYm+Fej7+VU7ulNmwVlFqBdLP2OA3/Rjcytbw/3Rp9pjvWc1T6kInBdN?= =?us-ascii?Q?MJ/Uf7Mt2nV5Xkkg8dJAQsD3IMc5hxMAnyKlVeXCbitQTnTPRyVdf5oBghUM?= =?us-ascii?Q?AHcjGv1DrPol7hldoIeksKzWbuot9Zf+gd9zWzis+25cAn1bnqjaVDRj9rg6?= =?us-ascii?Q?78QdZSH5eqqqQ75CW8Ju4FD/aXL3WofZICOQxzr83D69gAKVqgEAe809FWRD?= =?us-ascii?Q?aCcbl1Xe/YdJi84siCWw4UK+HOf/BMrFBWRpAaDza9wZRiDDetO4OpH6c2Q7?= =?us-ascii?Q?5FKMkzqIP9Zvd7S6z6qNbaoQE3Muh3V1Z5hA4eG8bSxjrNJhAaSKIB6LAXzG?= =?us-ascii?Q?ucsg+/WLyhqWGlVxLxrXtfcmqUrn1+tLAUoSckwjZkUz+s0RZ3aSKCcN7P0i?= =?us-ascii?Q?IGizgbELYXVfcwN+PvaEHPNI6ZFMVSl9ZEyEyC+mfnNEHQ0nb0w/LnDEFHcU?= =?us-ascii?Q?/MM+EP/0chyWI5N99/x4rVm5irUHClkRip6Clzzx1/MWbjOFewDnwu87fjsK?= =?us-ascii?Q?0QJsz8khSQ9UGqRLZJMG3NUtmiviIZqFZIoyHQYs/q5/25d/6JpB541WPyW8?= =?us-ascii?Q?FgBfX2gvg/Pb6vPz6GcSkM9GpD44C/wiuvmU7IbAgFvX9BIeEqaGJTnOlQDc?= =?us-ascii?Q?HTRRku50B4zdM2O0bdOpKmC6fvjS1siIuU4MgjsHTYW4Ul2sg=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; HKXPR06MB1014; 5:2ERlsa8w/MAIIz8Eyn8nghokOUJWgoszloMDft+JBPJdNCjgkQIUNPX2jUau7796SBrzJkl1ngUP4wT2H8yhlMS0Flhz6HB/982SZCNBDNgPdQsFgfYc/BCOQA0daeo720YjThbnKWplnsmLDVn9WA==; 24:0rGf2jbH9mvwIshU6+6VGTXaOVgalIl5B8nY43Yh8Kt8A28pO46GhSraT9MTu0uJrfKc026QlB+/R38+9DFv1r38bLwPmOc5SfKqkNzuCbA=; 20:qj8Zs6Mq5Sq2NZ4np06lw+wilAGYCnPh8/rBtzS8v4Ds2vntXqcfSKsxdMSBDQY4FlTeexaYxQa3JZI2S2vysfrRS+lifT/0eQixDlV1qwYqzrWNS19/XlQwlFc/At7upXbvhmrqivfT/+vEnYIU1qTyUCTz2LsTSaMa0HusxBs= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Oct 2015 08:43:57.8095 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HKXPR06MB1014 Cc: Linux-ALSA , Simon , Liam Girdwood Subject: [alsa-devel] [PATCH 18/18] ASoC: rsnd: use mod base common method on SSI-parent X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kuninori Morimoto Renesas sound needs many devices (SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp). SSI/SRC/CTU/MIX/DVC are implemented as module. SSI parent, SSIU are implemented as part of SSI CMD is implemented as part of CTU/MIX/DVC AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC It is nice sense that these all devices are implemented as mod. This patch makes SSI parent mod base common method Signed-off-by: Kuninori Morimoto --- sound/soc/sh/rcar/rsnd.h | 2 + sound/soc/sh/rcar/ssi.c | 301 +++++++++++++++++++++++++---------------------- 2 files changed, 161 insertions(+), 142 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 81c789f..599dfb6 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -211,6 +211,7 @@ enum rsnd_mod_type { RSND_MOD_CMD, RSND_MOD_SRC, RSND_MOD_SSIU, + RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, RSND_MOD_MAX, }; @@ -339,6 +340,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index bb08d66..3e81471 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -67,7 +67,9 @@ struct rsnd_ssi { u32 cr_own; u32 cr_clk; + u32 cr_mode; int chan; + int rate; int err; unsigned int usrcnt; }; @@ -82,9 +84,9 @@ struct rsnd_ssi { #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_parent(ssi) ((ssi)->parent) #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) +#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") @@ -168,7 +170,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -176,6 +180,21 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, unsigned int main_rate; unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); + if (!rsnd_rdai_is_clk_master(rdai)) + return 0; + + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return 0; + + if (ssi->usrcnt > 1) { + if (ssi->rate != rate) { + dev_err(dev, "SSI parent/child should use same rate\n"); + return -EINVAL; + } + + return 0; + } + /* * Find best clock, and try to start ADG */ @@ -193,6 +212,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(j); + ssi->rate = rate; + + rsnd_mod_write(mod, SSIWSR, CONT); + dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), rsnd_mod_id(mod), rate); @@ -205,113 +228,26 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, return -EIO; } -static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - - ssi->cr_clk = 0; - rsnd_adg_ssi_clk_stop(mod); -} - -static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, - struct rsnd_dai_stream *io) +static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, + struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod *mod = rsnd_mod_get(ssi); - u32 cr_mode; - u32 cr; - - if (0 == ssi->usrcnt) { - rsnd_mod_power_on(mod); - - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); - - if (ssi_parent) - rsnd_ssi_hw_start(ssi_parent, io); - else - rsnd_ssi_master_clk_start(ssi, io); - } - } - - if (rsnd_ssi_is_dma_mode(mod)) { - cr_mode = UIEN | OIEN | /* over/under run */ - DMEN; /* DMA : enable DMA */ - } else { - cr_mode = DIEN; /* PIO : enable Data interrupt */ - } - - cr = ssi->cr_own | - ssi->cr_clk | - cr_mode | - EN; - - rsnd_mod_write(mod, SSICR, cr); - - /* enable WS continue */ - if (rsnd_rdai_is_clk_master(rdai)) - rsnd_mod_write(mod, SSIWSR, CONT); - - /* clear error status */ - rsnd_ssi_status_clear(mod); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - ssi->usrcnt++; - - dev_dbg(dev, "%s[%d] hw started\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); -} - -static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 cr; - - if (0 == ssi->usrcnt) { - dev_err(dev, "%s called without starting\n", __func__); + if (!rsnd_rdai_is_clk_master(rdai)) return; - } - - ssi->usrcnt--; - - if (0 == ssi->usrcnt) { - /* - * disable all IRQ, - * and, wait all data was sent - */ - cr = ssi->cr_own | - ssi->cr_clk; - - rsnd_mod_write(mod, SSICR, cr | EN); - rsnd_ssi_status_check(mod, DIRQ); - - /* - * disable SSI, - * and, wait idle state - */ - rsnd_mod_write(mod, SSICR, cr); /* disabled all */ - rsnd_ssi_status_check(mod, IIRQ); - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); - - if (ssi_parent) - rsnd_ssi_hw_stop(io, ssi_parent); - else - rsnd_ssi_master_clk_stop(ssi); - } + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return; - rsnd_mod_power_off(mod); + if (ssi->usrcnt > 1) + return; - ssi->chan = 0; - } + ssi->cr_clk = 0; + ssi->rate = 0; - dev_dbg(dev, "%s[%d] hw stopped\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + rsnd_adg_ssi_clk_stop(mod); } /* @@ -325,6 +261,18 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 cr; + int ret; + + ssi->usrcnt++; + + rsnd_mod_power_on(mod); + + ret = rsnd_ssi_master_clk_start(ssi, io); + if (ret < 0) + return ret; + + if (rsnd_ssi_is_parent(mod, io)) + return 0; cr = FORCE; @@ -359,12 +307,24 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (rsnd_io_is_play(io)) cr |= TRMD; - /* - * set ssi parameter - */ ssi->cr_own = cr; + + if (rsnd_ssi_is_dma_mode(mod)) { + cr = UIEN | OIEN | /* over/under run */ + DMEN; /* DMA : enable DMA */ + } else { + cr = DIEN; /* PIO : enable Data interrupt */ + } + + ssi->cr_mode = cr; + ssi->err = -1; /* ignore 1st error */ + /* clear error status */ + rsnd_ssi_status_clear(mod); + + rsnd_ssi_irq_enable(mod); + return 0; } @@ -375,6 +335,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); + if (rsnd_ssi_is_parent(mod, io)) + goto rsnd_ssi_quit_end; + if (ssi->err > 0) dev_warn(dev, "%s[%d] under/over flow err = %d\n", rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); @@ -382,6 +345,19 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, ssi->cr_own = 0; ssi->err = 0; + rsnd_ssi_irq_disable(mod); + +rsnd_ssi_quit_end: + rsnd_ssi_master_clk_stop(ssi, io); + + rsnd_mod_power_off(mod); + + ssi->usrcnt--; + + if (ssi->usrcnt < 0) + dev_err(dev, "%s[%d] usrcnt error\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + return 0; } @@ -391,14 +367,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *params) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); int chan = params_channels(params); /* * Already working. * It will happen if SSI has parent/child connection. */ - if (ssi->usrcnt) { + if (ssi->usrcnt > 1) { /* * it is error if child <-> parent SSI uses * different channels. @@ -407,11 +382,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return -EIO; } - /* It will be removed on rsnd_ssi_hw_stop */ ssi->chan = chan; - if (ssi_parent) - return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io, - substream, params); return 0; } @@ -432,15 +403,59 @@ static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) return status; } +static int __rsnd_ssi_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + cr = ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode | + EN; + + rsnd_mod_write(mod, SSICR, cr); + + return 0; +} + static int rsnd_ssi_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + /* + * no limit to start + * see also + * rsnd_ssi_stop + * rsnd_ssi_interrupt + */ + return __rsnd_ssi_start(mod, io, priv); +} + +static int __rsnd_ssi_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + /* + * disable all IRQ, + * and, wait all data was sent + */ + cr = ssi->cr_own | + ssi->cr_clk; - rsnd_ssi_hw_start(ssi, io); + rsnd_mod_write(mod, SSICR, cr | EN); + rsnd_ssi_status_check(mod, DIRQ); - rsnd_ssi_irq_enable(mod); + /* + * disable SSI, + * and, wait idle state + */ + rsnd_mod_write(mod, SSICR, cr); /* disabled all */ + rsnd_ssi_status_check(mod, IIRQ); return 0; } @@ -451,13 +466,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - rsnd_ssi_irq_disable(mod); - - rsnd_ssi_record_error(ssi); - - rsnd_ssi_hw_stop(io, ssi); + /* + * don't stop if not last user + * see also + * rsnd_ssi_start + * rsnd_ssi_interrupt + */ + if (ssi->usrcnt > 1) + return 0; - return 0; + return __rsnd_ssi_stop(mod, io, priv); } static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, @@ -505,8 +523,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - rsnd_ssi_stop(mod, io, priv); - rsnd_ssi_start(mod, io, priv); + __rsnd_ssi_stop(mod, io, priv); + __rsnd_ssi_start(mod, io, priv); } if (ssi->err > 1024) { @@ -535,6 +553,27 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) /* * SSI PIO */ +static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (!__rsnd_ssi_is_pin_sharing(mod)) + return; + + switch (rsnd_mod_id(mod)) { + case 1: + case 2: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); + break; + case 4: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); + break; + case 8: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); + break; + } +} + static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -543,6 +582,8 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; + rsnd_ssi_parent_attach(mod, io, priv); + ret = rsnd_ssiu_attach(io, mod); if (ret < 0) return ret; @@ -679,28 +720,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - - if (!__rsnd_ssi_is_pin_sharing(mod)) - return; - - switch (rsnd_mod_id(mod)) { - case 1: - case 2: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); - break; - case 4: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); - break; - case 8: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); - break; - } -} - - static void rsnd_of_parse_ssi(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) @@ -810,8 +829,6 @@ int rsnd_ssi_probe(struct platform_device *pdev, RSND_MOD_SSI, i); if (ret) return ret; - - rsnd_ssi_parent_setup(priv, ssi); } return 0;