Skip to content

Commit

Permalink
mtd: gpmi: change the code for clocks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Huang Shijie authored and David Woodhouse committed Sep 29, 2012
1 parent 894824f commit ff50617
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 18 deletions.
45 changes: 37 additions & 8 deletions drivers/mtd/nand/gpmi-nand/gpmi-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,42 @@ static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -784,8 +814,7 @@ void gpmi_begin(struct gpmi_nand_data *this)

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. */
Expand Down
82 changes: 73 additions & 9 deletions drivers/mtd/nand/gpmi-nand/gpmi-nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,78 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
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;

Expand All @@ -493,12 +562,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:
Expand All @@ -513,9 +579,7 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)

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);
Expand Down
3 changes: 2 additions & 1 deletion drivers/mtd/nand/gpmi-nand/gpmi-nand.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@
#include <linux/dma-mapping.h>
#include <linux/fsl/mxs-dma.h>

#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
struct resources {
void *gpmi_regs;
void *bch_regs;
unsigned int bch_low_interrupt;
unsigned int bch_high_interrupt;
unsigned int dma_low_channel;
unsigned int dma_high_channel;
struct clk *clock;
struct clk *clock[GPMI_CLK_MAX];
};

/**
Expand Down

0 comments on commit ff50617

Please sign in to comment.