aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/gpmi-nand
diff options
context:
space:
mode:
authorHuang Shijie <shijie8@gmail.com>2012-07-02 21:39:32 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-09-29 09:50:02 -0400
commitff506172a30080963853dc0d259566c82fe8626c (patch)
tree2959ffd3912316c17e19a645310e86bf36859600 /drivers/mtd/nand/gpmi-nand
parent894824f9731a805b70b553220ae58e5475ff6ff1 (diff)
mtd: gpmi: change the code for clocks
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 <shijie8@gmail.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand/gpmi-nand')
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c45
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c82
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h3
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 a1f43329ad43..6bb0998dcb40 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -124,12 +124,42 @@ error:
124 return -ETIMEDOUT; 124 return -ETIMEDOUT;
125} 125}
126 126
127static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
128{
129 struct clk *clk;
130 int ret;
131 int i;
132
133 for (i = 0; i < GPMI_CLK_MAX; i++) {
134 clk = this->resources.clock[i];
135 if (!clk)
136 break;
137
138 if (v) {
139 ret = clk_prepare_enable(clk);
140 if (ret)
141 goto err_clk;
142 } else {
143 clk_disable_unprepare(clk);
144 }
145 }
146 return 0;
147
148err_clk:
149 for (; i > 0; i--)
150 clk_disable_unprepare(this->resources.clock[i - 1]);
151 return ret;
152}
153
154#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
155#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
156
127int gpmi_init(struct gpmi_nand_data *this) 157int gpmi_init(struct gpmi_nand_data *this)
128{ 158{
129 struct resources *r = &this->resources; 159 struct resources *r = &this->resources;
130 int ret; 160 int ret;
131 161
132 ret = clk_prepare_enable(r->clock); 162 ret = gpmi_enable_clk(this);
133 if (ret) 163 if (ret)
134 goto err_out; 164 goto err_out;
135 ret = gpmi_reset_block(r->gpmi_regs, false); 165 ret = gpmi_reset_block(r->gpmi_regs, false);
@@ -149,7 +179,7 @@ int gpmi_init(struct gpmi_nand_data *this)
149 /* Select BCH ECC. */ 179 /* Select BCH ECC. */
150 writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); 180 writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
151 181
152 clk_disable_unprepare(r->clock); 182 gpmi_disable_clk(this);
153 return 0; 183 return 0;
154err_out: 184err_out:
155 return ret; 185 return ret;
@@ -205,7 +235,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
205 ecc_strength = bch_geo->ecc_strength >> 1; 235 ecc_strength = bch_geo->ecc_strength >> 1;
206 page_size = bch_geo->page_size; 236 page_size = bch_geo->page_size;
207 237
208 ret = clk_prepare_enable(r->clock); 238 ret = gpmi_enable_clk(this);
209 if (ret) 239 if (ret)
210 goto err_out; 240 goto err_out;
211 241
@@ -240,7 +270,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
240 writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, 270 writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
241 r->bch_regs + HW_BCH_CTRL_SET); 271 r->bch_regs + HW_BCH_CTRL_SET);
242 272
243 clk_disable_unprepare(r->clock); 273 gpmi_disable_clk(this);
244 return 0; 274 return 0;
245err_out: 275err_out:
246 return ret; 276 return ret;
@@ -716,7 +746,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
716 int ret; 746 int ret;
717 747
718 /* Enable the clock. */ 748 /* Enable the clock. */
719 ret = clk_prepare_enable(r->clock); 749 ret = gpmi_enable_clk(this);
720 if (ret) { 750 if (ret) {
721 pr_err("We failed in enable the clk\n"); 751 pr_err("We failed in enable the clk\n");
722 goto err_out; 752 goto err_out;
@@ -727,7 +757,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
727 gpmi_regs + HW_GPMI_TIMING1); 757 gpmi_regs + HW_GPMI_TIMING1);
728 758
729 /* Get the timing information we need. */ 759 /* Get the timing information we need. */
730 nfc->clock_frequency_in_hz = clk_get_rate(r->clock); 760 nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
731 clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; 761 clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz;
732 762
733 gpmi_nfc_compute_hardware_timing(this, &hw); 763 gpmi_nfc_compute_hardware_timing(this, &hw);
@@ -784,8 +814,7 @@ err_out:
784 814
785void gpmi_end(struct gpmi_nand_data *this) 815void gpmi_end(struct gpmi_nand_data *this)
786{ 816{
787 struct resources *r = &this->resources; 817 gpmi_disable_clk(this);
788 clk_disable_unprepare(r->clock);
789} 818}
790 819
791/* Clears a BCH interrupt. */ 820/* 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 9da9ee88a824..8c0d2f0a526f 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -465,9 +465,78 @@ acquire_err:
465 return -EINVAL; 465 return -EINVAL;
466} 466}
467 467
468static void gpmi_put_clks(struct gpmi_nand_data *this)
469{
470 struct resources *r = &this->resources;
471 struct clk *clk;
472 int i;
473
474 for (i = 0; i < GPMI_CLK_MAX; i++) {
475 clk = r->clock[i];
476 if (clk) {
477 clk_put(clk);
478 r->clock[i] = NULL;
479 }
480 }
481}
482
483static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
484 "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
485};
486
487static int __devinit gpmi_get_clks(struct gpmi_nand_data *this)
488{
489 struct resources *r = &this->resources;
490 char **extra_clks = NULL;
491 struct clk *clk;
492 int i;
493
494 /* The main clock is stored in the first. */
495 r->clock[0] = clk_get(this->dev, "gpmi_io");
496 if (IS_ERR(r->clock[0]))
497 goto err_clock;
498
499 /* Get extra clocks */
500 if (GPMI_IS_MX6Q(this))
501 extra_clks = extra_clks_for_mx6q;
502 if (!extra_clks)
503 return 0;
504
505 for (i = 1; i < GPMI_CLK_MAX; i++) {
506 if (extra_clks[i - 1] == NULL)
507 break;
508
509 clk = clk_get(this->dev, extra_clks[i - 1]);
510 if (IS_ERR(clk))
511 goto err_clock;
512
513 r->clock[i] = clk;
514 }
515
516 if (GPMI_IS_MX6Q(this)) {
517 /*
518 * Set the default values for the clocks in mx6q:
519 * The main clock(enfc) : 22MHz
520 * The others : 44.5MHz
521 *
522 * These are just the default values. If you want to use
523 * the ONFI nand which is in the Synchronous Mode, you should
524 * change the clocks's frequencies as you need.
525 */
526 clk_set_rate(r->clock[0], 22000000);
527 for (i = 1; i < GPMI_CLK_MAX && r->clock[i]; i++)
528 clk_set_rate(r->clock[i], 44500000);
529 }
530 return 0;
531
532err_clock:
533 dev_dbg(this->dev, "failed in finding the clocks.\n");
534 gpmi_put_clks(this);
535 return -ENOMEM;
536}
537
468static int __devinit acquire_resources(struct gpmi_nand_data *this) 538static int __devinit acquire_resources(struct gpmi_nand_data *this)
469{ 539{
470 struct resources *res = &this->resources;
471 struct pinctrl *pinctrl; 540 struct pinctrl *pinctrl;
472 int ret; 541 int ret;
473 542
@@ -493,12 +562,9 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
493 goto exit_pin; 562 goto exit_pin;
494 } 563 }
495 564
496 res->clock = clk_get(&this->pdev->dev, NULL); 565 ret = gpmi_get_clks(this);
497 if (IS_ERR(res->clock)) { 566 if (ret)
498 pr_err("can not get the clock\n");
499 ret = -ENOENT;
500 goto exit_clock; 567 goto exit_clock;
501 }
502 return 0; 568 return 0;
503 569
504exit_clock: 570exit_clock:
@@ -513,9 +579,7 @@ exit_regs:
513 579
514static void release_resources(struct gpmi_nand_data *this) 580static void release_resources(struct gpmi_nand_data *this)
515{ 581{
516 struct resources *r = &this->resources; 582 gpmi_put_clks(this);
517
518 clk_put(r->clock);
519 release_register_block(this); 583 release_register_block(this);
520 release_bch_irq(this); 584 release_bch_irq(this);
521 release_dma_channels(this); 585 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 ce5daa160920..1547a60c1c6f 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -22,6 +22,7 @@
22#include <linux/dma-mapping.h> 22#include <linux/dma-mapping.h>
23#include <linux/fsl/mxs-dma.h> 23#include <linux/fsl/mxs-dma.h>
24 24
25#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
25struct resources { 26struct resources {
26 void *gpmi_regs; 27 void *gpmi_regs;
27 void *bch_regs; 28 void *bch_regs;
@@ -29,7 +30,7 @@ struct resources {
29 unsigned int bch_high_interrupt; 30 unsigned int bch_high_interrupt;
30 unsigned int dma_low_channel; 31 unsigned int dma_low_channel;
31 unsigned int dma_high_channel; 32 unsigned int dma_high_channel;
32 struct clk *clock; 33 struct clk *clock[GPMI_CLK_MAX];
33}; 34};
34 35
35/** 36/**