From patchwork Tue Jul 3 01:39:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Huang Shijie X-Patchwork-Id: 1146811 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 36F93DFFAD for ; Mon, 2 Jul 2012 13:47:45 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1SlguB-0002sU-Nf; Mon, 02 Jul 2012 13:43:07 +0000 Received: from mail-pb0-f49.google.com ([209.85.160.49]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SlgrD-0002gE-Jx; Mon, 02 Jul 2012 13:40:07 +0000 Received: by mail-pb0-f49.google.com with SMTP id rq13so8564249pbb.36 for ; Mon, 02 Jul 2012 06:39:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=PlncqMrxDGJG9xgJE4Kr2pBR4ra+tq7MyCoSUbr3Uw4=; b=wP/y1fpvOQ/2yozWM2KbtUqwVcNdSgYKwYOZl2QUQvWGIJT+k9pM4ervLtkEC1V5DJ MAehrG4SlwVVUwqXFTjlpo5ruRBvAHmzHqNOeFeKQsO3AhJ2kLQH4Se+bB/PAldMuvPj 6kAUUKiHF5xXH0cfiOATgoR2qWWVwcgk89QCRKumEqtZz9HWHoYQOHUZeVYE9g33chKa BcZZigBOkMsRlf9K1NUx3lLcg02hEL05zxwExgeKTOm9tinF+MDP8M881c9FXPuaZqxv Sf/TBpIwBqtoYo4osy9HjP13LzqqZARSesXG4Ev0JIHHKo9wwILVdP0jZUdqNMk2UED1 m0Tg== Received: by 10.68.231.8 with SMTP id tc8mr30176331pbc.140.1341236399088; Mon, 02 Jul 2012 06:39:59 -0700 (PDT) Received: from localhost.localdomain.Home ([218.81.180.228]) by mx.google.com with ESMTPS id ka5sm13030126pbb.37.2012.07.02.06.39.55 (version=SSLv3 cipher=OTHER); Mon, 02 Jul 2012 06:39:58 -0700 (PDT) From: Huang Shijie To: shawn.guo@linaro.org Subject: [PATCH v4 2/2] mtd: gpmi: change the code for clocks Date: Mon, 2 Jul 2012 21:39:32 -0400 Message-Id: <1341279572-6098-3-git-send-email-shijie8@gmail.com> X-Mailer: git-send-email 1.7.4.4 In-Reply-To: <1341279572-6098-1-git-send-email-shijie8@gmail.com> References: <1341279572-6098-1-git-send-email-shijie8@gmail.com> X-Spam-Note: CRM114 invocation failed X-Spam-Score: -0.5 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-0.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (shijie8[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.160.49 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 1.9 DATE_IN_FUTURE_06_12 Date: is 6 to 12 hours after Received: date 0.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends in digit (shijie8[at]gmail.com) -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Huang Shijie , dong.aisheng@linaro.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, dedekind1@gmail.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org The gpmi nand driver may needs several clocks(MX6Q needs five clocks). In the old clock framework, all these clocks are chained together, all you need is to manipulate the first clock. But the kernel uses the common clk framework now, which forces us to get the clocks one by one. When we use them, we have to enable them one by one too. Signed-off-by: Huang Shijie --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 45 ++++++++++++++--- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 82 ++++++++++++++++++++++++++++---- drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 3 +- 3 files changed, 112 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index a1f4332..6bb0998 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -124,12 +124,42 @@ error: return -ETIMEDOUT; } +static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v) +{ + struct clk *clk; + int ret; + int i; + + for (i = 0; i < GPMI_CLK_MAX; i++) { + clk = this->resources.clock[i]; + if (!clk) + break; + + if (v) { + ret = clk_prepare_enable(clk); + if (ret) + goto err_clk; + } else { + clk_disable_unprepare(clk); + } + } + return 0; + +err_clk: + for (; i > 0; i--) + clk_disable_unprepare(this->resources.clock[i - 1]); + return ret; +} + +#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) +#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) + int gpmi_init(struct gpmi_nand_data *this) { struct resources *r = &this->resources; int ret; - ret = clk_prepare_enable(r->clock); + ret = gpmi_enable_clk(this); if (ret) goto err_out; ret = gpmi_reset_block(r->gpmi_regs, false); @@ -149,7 +179,7 @@ int gpmi_init(struct gpmi_nand_data *this) /* Select BCH ECC. */ writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); - clk_disable_unprepare(r->clock); + gpmi_disable_clk(this); return 0; err_out: return ret; @@ -205,7 +235,7 @@ int bch_set_geometry(struct gpmi_nand_data *this) ecc_strength = bch_geo->ecc_strength >> 1; page_size = bch_geo->page_size; - ret = clk_prepare_enable(r->clock); + ret = gpmi_enable_clk(this); if (ret) goto err_out; @@ -240,7 +270,7 @@ int bch_set_geometry(struct gpmi_nand_data *this) writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, r->bch_regs + HW_BCH_CTRL_SET); - clk_disable_unprepare(r->clock); + gpmi_disable_clk(this); return 0; err_out: return ret; @@ -716,7 +746,7 @@ void gpmi_begin(struct gpmi_nand_data *this) int ret; /* Enable the clock. */ - ret = clk_prepare_enable(r->clock); + ret = gpmi_enable_clk(this); if (ret) { pr_err("We failed in enable the clk\n"); goto err_out; @@ -727,7 +757,7 @@ void gpmi_begin(struct gpmi_nand_data *this) gpmi_regs + HW_GPMI_TIMING1); /* Get the timing information we need. */ - nfc->clock_frequency_in_hz = clk_get_rate(r->clock); + nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]); clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; gpmi_nfc_compute_hardware_timing(this, &hw); @@ -784,8 +814,7 @@ err_out: void gpmi_end(struct gpmi_nand_data *this) { - struct resources *r = &this->resources; - clk_disable_unprepare(r->clock); + gpmi_disable_clk(this); } /* Clears a BCH interrupt. */ diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index a6cad5c..b821517 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -464,9 +464,78 @@ acquire_err: return -EINVAL; } +static void gpmi_put_clks(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct clk *clk; + int i; + + for (i = 0; i < GPMI_CLK_MAX; i++) { + clk = r->clock[i]; + if (clk) { + clk_put(clk); + r->clock[i] = NULL; + } + } +} + +static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { + "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", +}; + +static int __devinit gpmi_get_clks(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + char **extra_clks = NULL; + struct clk *clk; + int i; + + /* The main clock is stored in the first. */ + r->clock[0] = clk_get(this->dev, "gpmi_io"); + if (IS_ERR(r->clock[0])) + goto err_clock; + + /* Get extra clocks */ + if (GPMI_IS_MX6Q(this)) + extra_clks = extra_clks_for_mx6q; + if (!extra_clks) + return 0; + + for (i = 1; i < GPMI_CLK_MAX; i++) { + if (extra_clks[i - 1] == NULL) + break; + + clk = clk_get(this->dev, extra_clks[i - 1]); + if (IS_ERR(clk)) + goto err_clock; + + r->clock[i] = clk; + } + + if (GPMI_IS_MX6Q(this)) { + /* + * Set the default values for the clocks in mx6q: + * The main clock(enfc) : 22MHz + * The others : 44.5MHz + * + * These are just the default values. If you want to use + * the ONFI nand which is in the Synchronous Mode, you should + * change the clocks's frequencies as you need. + */ + clk_set_rate(r->clock[0], 22000000); + for (i = 1; i < GPMI_CLK_MAX && r->clock[i]; i++) + clk_set_rate(r->clock[i], 44500000); + } + return 0; + +err_clock: + dev_dbg(this->dev, "failed in finding the clocks.\n"); + gpmi_put_clks(this); + return -ENOMEM; +} + static int __devinit acquire_resources(struct gpmi_nand_data *this) { - struct resources *res = &this->resources; struct pinctrl *pinctrl; int ret; @@ -492,12 +561,9 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this) goto exit_pin; } - res->clock = clk_get(&this->pdev->dev, NULL); - if (IS_ERR(res->clock)) { - pr_err("can not get the clock\n"); - ret = -ENOENT; + ret = gpmi_get_clks(this); + if (ret) goto exit_clock; - } return 0; exit_clock: @@ -512,9 +578,7 @@ exit_regs: static void release_resources(struct gpmi_nand_data *this) { - struct resources *r = &this->resources; - - clk_put(r->clock); + gpmi_put_clks(this); release_register_block(this); release_bch_irq(this); release_dma_channels(this); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index ce5daa1..1547a60 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -22,6 +22,7 @@ #include #include +#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */ struct resources { void *gpmi_regs; void *bch_regs; @@ -29,7 +30,7 @@ struct resources { unsigned int bch_high_interrupt; unsigned int dma_low_channel; unsigned int dma_high_channel; - struct clk *clock; + struct clk *clock[GPMI_CLK_MAX]; }; /**