diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2009-07-20 22:55:14 +0000 |
---|---|---|
committer | Lars-Peter Clausen <lars@metafoo.de> | 2009-07-20 22:55:14 +0000 |
commit | 8353477e5ae8918070d5782bb78248a424d00149 (patch) | |
tree | 0f800e729b1d94d020e534eff39ec3ddeb29f710 /target | |
parent | f7bf9bee328db624802233ed87aa745154c7950a (diff) | |
download | master-187ad058-8353477e5ae8918070d5782bb78248a424d00149.tar.gz master-187ad058-8353477e5ae8918070d5782bb78248a424d00149.tar.bz2 master-187ad058-8353477e5ae8918070d5782bb78248a424d00149.zip |
[s3c24xx] glamo-mci: Cleanup mmc clock rate control.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@16936 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target')
5 files changed, 325 insertions, 409 deletions
diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.c b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.c index 1a6adcdeae..60cfae843f 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.c +++ b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.c @@ -76,6 +76,7 @@ struct reg_range { char *name; char dump; }; + struct reg_range reg_range[] = { { 0x0000, 0x76, "General", 1 }, { 0x0200, 0x18, "Host Bus", 1 }, @@ -86,7 +87,7 @@ struct reg_range reg_range[] = { /* { 0x0c00, 0xcc, "MPEG", 0 }, */ { 0x1100, 0xb2, "LCD 1", 1 }, { 0x1200, 0x64, "LCD 2", 1 }, - { 0x1400, 0x40, "MMC", 1 }, + { 0x1400, 0x42, "MMC", 1 }, /* { 0x1500, 0x080, "MPU 0", 0 }, { 0x1580, 0x080, "MPU 1", 0 }, { 0x1600, 0x080, "Cmd Queue", 0 }, @@ -478,7 +479,7 @@ int __glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine) break; case GLAMO_ENGINE_2D: __reg_set_bit_mask(glamo, GLAMO_REG_CLOCK_2D, - GLAMO_CLOCK_2D_EN_M7CLK | + GLAMO_CLOCK_2D_EN_M7CLK | GLAMO_CLOCK_2D_EN_GCLK | GLAMO_CLOCK_2D_DG_M7CLK | GLAMO_CLOCK_2D_DG_GCLK, @@ -544,7 +545,40 @@ u_int16_t glamo_engine_clkreg_get(struct glamo_core *glamo, } EXPORT_SYMBOL_GPL(glamo_engine_clkreg_get); -struct glamo_script reset_regs[] = { +static const struct glamo_script engine_div_regs[__NUM_GLAMO_ENGINES] = { + [GLAMO_ENGINE_LCD] = {GLAMO_REG_CLOCK_GEN5_1, GLAMO_CLOCK_GEN51_EN_DIV_DCLK}, + [GLAMO_ENGINE_MMC] = {GLAMO_REG_CLOCK_GEN5_1, GLAMO_CLOCK_GEN51_EN_DIV_TCLK}, + [GLAMO_ENGINE_2D] = {GLAMO_REG_CLOCK_GEN5_1, GLAMO_CLOCK_GEN51_EN_DIV_GCLK}, +}; + +void glamo_engine_div_enable(struct glamo_core *glamo, enum glamo_engine engine) +{ + uint16_t reg = engine_div_regs[engine].reg; + uint16_t bit = engine_div_regs[engine].val; + uint16_t val; + + spin_lock(&glamo->lock); + val = __reg_read(glamo, reg); + __reg_write(glamo, reg, val | bit); + spin_unlock(&glamo->lock); + mdelay(5); +} +EXPORT_SYMBOL_GPL(glamo_engine_div_enable); + +void glamo_engine_div_disable(struct glamo_core *glamo, enum glamo_engine engine) +{ + uint16_t reg = engine_div_regs[engine].reg; + uint16_t bit = engine_div_regs[engine].val; + uint16_t val; + + spin_lock(&glamo->lock); + val = __reg_read(glamo, reg); + __reg_write(glamo, reg, val & ~bit); + spin_unlock(&glamo->lock); +} +EXPORT_SYMBOL_GPL(glamo_engine_div_disable); + +static const struct glamo_script reset_regs[] = { [GLAMO_ENGINE_LCD] = { GLAMO_REG_CLOCK_LCD, GLAMO_CLOCK_LCD_RESET }, @@ -572,18 +606,18 @@ struct glamo_script reset_regs[] = { void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine) { - struct glamo_script *rst; + uint16_t reg = reset_regs[engine].reg; + uint16_t val = reset_regs[engine].val; if (engine >= ARRAY_SIZE(reset_regs)) { dev_warn(&glamo->pdev->dev, "unknown engine %u ", engine); return; } - rst = &reset_regs[engine]; spin_lock(&glamo->lock); - __reg_set_bit(glamo, rst->reg, rst->val); - __reg_clear_bit(glamo, rst->reg, rst->val); + __reg_set_bit(glamo, reg, val); + __reg_clear_bit(glamo, reg, val); spin_unlock(&glamo->lock); } EXPORT_SYMBOL_GPL(glamo_engine_reset); @@ -599,21 +633,12 @@ void glamo_lcm_reset(struct platform_device *pdev, int level) } EXPORT_SYMBOL_GPL(glamo_lcm_reset); -enum glamo_pll { - GLAMO_PLL1, - GLAMO_PLL2, -}; - -static int glamo_pll_rate(struct glamo_core *glamo, +int glamo_pll_rate(struct glamo_core *glamo, enum glamo_pll pll) { u_int16_t reg; - unsigned int div = 512; unsigned int osci = glamo->pdata->osci_clock_rate; - if (osci == 32768) - div = 1; - switch (pll) { case GLAMO_PLL1: reg = __reg_read(glamo, GLAMO_REG_PLL_GEN1); @@ -624,18 +649,19 @@ static int glamo_pll_rate(struct glamo_core *glamo, default: return -EINVAL; } - return (osci/div)*reg; + return osci*reg; } +EXPORT_SYMBOL_GPL(glamo_pll_rate); int glamo_engine_reclock(struct glamo_core *glamo, enum glamo_engine engine, - int ps) + int hz) { - int pll, khz; - u_int16_t reg, mask, val = 0; + int pll; + u_int16_t reg, mask, div; - if (!ps) - return 0; + if (!hz) + return -EINVAL; switch (engine) { case GLAMO_ENGINE_LCD: @@ -643,6 +669,11 @@ int glamo_engine_reclock(struct glamo_core *glamo, reg = GLAMO_REG_CLOCK_GEN7; mask = 0xff; break; + case GLAMO_ENGINE_MMC: + pll = GLAMO_PLL1; + reg = GLAMO_REG_CLOCK_GEN8; + mask = 0xff; + break; default: dev_warn(&glamo->pdev->dev, "reclock of engine 0x%x not supported\n", engine); @@ -651,23 +682,22 @@ int glamo_engine_reclock(struct glamo_core *glamo, } pll = glamo_pll_rate(glamo, pll); - khz = 1000000000UL / ps; - if (khz) - val = (pll / khz) / 1000; + div = pll / hz; + + if (div != 0 && pll / div <= hz) + --div; + + if (div > mask) + div = mask; dev_dbg(&glamo->pdev->dev, - "PLL %d, kHZ %d, div %d\n", pll, khz, val); + "PLL %d, kHZ %d, div %d\n", pll, hz / 1000, div); - if (val) { - val--; - reg_set_bit_mask(glamo, reg, mask, val); - mdelay(5); /* wait some time to stabilize */ + reg_set_bit_mask(glamo, reg, mask, div); + mdelay(5); /* wait some time to stabilize */ - return 0; - } else { - return -EINVAL; - } + return pll / (div + 1); } EXPORT_SYMBOL_GPL(glamo_engine_reclock); @@ -675,7 +705,7 @@ EXPORT_SYMBOL_GPL(glamo_engine_reclock); * script support ***********************************************************************/ -int glamo_run_script(struct glamo_core *glamo, struct glamo_script *script, +int glamo_run_script(struct glamo_core *glamo, const struct glamo_script *script, int len, int may_sleep) { int i; @@ -746,7 +776,7 @@ int glamo_run_script(struct glamo_core *glamo, struct glamo_script *script, } EXPORT_SYMBOL(glamo_run_script); -static struct glamo_script glamo_init_script[] = { +static const struct glamo_script glamo_init_script[] = { { GLAMO_REG_CLOCK_HOST, 0x1000 }, { 0xfffe, 2 }, { GLAMO_REG_CLOCK_MEMORY, 0x1000 }, diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.h b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.h index 4675371025..f0c2ec3ee2 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.h +++ b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-core.h @@ -17,6 +17,11 @@ #define GLAMO_MMC_BUFFER_SIZE (64 * 1024) #define GLAMO_FB_SIZE (GLAMO_INTERNAL_RAM_SIZE - GLAMO_MMC_BUFFER_SIZE) +enum glamo_pll { + GLAMO_PLL1, + GLAMO_PLL2, +}; + struct glamo_core { int irq; int irq_works; /* 0 means PCB does not support Glamo IRQ */ @@ -38,8 +43,14 @@ struct glamo_script { u_int16_t val; }; +void glamo_engine_div_enable(struct glamo_core *glamo, enum glamo_engine engine); +void glamo_engine_div_disable(struct glamo_core *glamo, enum glamo_engine engine); + + +int glamo_pll_rate(struct glamo_core *glamo, enum glamo_pll pll); + int glamo_run_script(struct glamo_core *glamo, - struct glamo_script *script, int len, int may_sleep); + const struct glamo_script *script, int len, int may_sleep); int glamo_engine_enable(struct glamo_core *glamo, enum glamo_engine engine); int glamo_engine_disable(struct glamo_core *glamo, enum glamo_engine engine); diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-fb.c b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-fb.c index 07a5251747..59491720e2 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-fb.c +++ b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-fb.c @@ -321,7 +321,7 @@ static void glamofb_program_mode(struct glamofb_handle* gfb) { if (var->pixclock) glamo_engine_reclock(gcore, GLAMO_ENGINE_LCD, - gfb->fb->var.pixclock); + (1000000000UL / gfb->fb->var.pixclock) * 1000); reg_set_bit_mask(gfb, GLAMO_REG_LCD_WIDTH, diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c index ef39017ec6..37373f5d18 100644 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c +++ b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c @@ -23,15 +23,41 @@ #include <linux/crc7.h> #include <linux/scatterlist.h> #include <linux/io.h> +#include <linux/regulator/consumer.h> #include <linux/mfd/glamo.h> -#include "glamo-mci.h" #include "glamo-core.h" #include "glamo-regs.h" #define DRIVER_NAME "glamo-mci" -static void glamo_mci_send_request(struct mmc_host *mmc); +struct glamo_mci_host { + struct platform_device *pdev; + struct glamo_mmc_platform_data *pdata; + struct mmc_host *mmc; + struct resource *mmio_mem; + struct resource *data_mem; + void __iomem *mmio_base; + u16 __iomem *data_base; + + struct regulator *regulator; + struct mmc_request *mrq; + + unsigned int clk_rate; + + unsigned short vdd; + char power_mode; + + unsigned char request_counter; + + struct timer_list disable_timer; + + struct work_struct irq_work; + + unsigned clk_enabled : 1; +}; + +static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request* mrq); static void glamo_mci_send_command(struct glamo_mci_host *host, struct mmc_command *cmd); @@ -48,7 +74,7 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, * for example */ -static int sd_max_clk = 50000000 / 3; +static int sd_max_clk = 50000000; module_param(sd_max_clk, int, 0644); /* @@ -85,35 +111,6 @@ static int sd_post_power_clock = 1000000; module_param(sd_post_power_clock, int, 0644); -/* - * SD Signal drive strength - * - * you can override this on kernel commandline using - * - * glamo_mci.sd_drive=0 - * - * for example - */ - -static int sd_drive; -module_param(sd_drive, int, 0644); - -/* - * SD allow SD clock to run while idle - * - * you can override this on kernel commandline using - * - * glamo_mci.sd_idleclk=0 - * - * for example - */ - -static int sd_idleclk = 0; /* disallow idle clock by default */ -module_param(sd_idleclk, int, 0644); - -/* used to stash real idleclk state in suspend: we force it to run in there */ -static int suspend_sd_idleclk; - static inline void glamo_reg_write(struct glamo_mci_host *glamo, u_int16_t reg, u_int16_t val) { @@ -140,11 +137,34 @@ static void glamo_reg_set_bit_mask(struct glamo_mci_host *glamo, glamo_reg_write(glamo, reg, tmp); } -static void do_pio_read(struct glamo_mci_host *host) +static void glamo_mci_clock_disable(struct glamo_mci_host *host) { + if (host->clk_enabled) { +/* glamo_engine_div_disable(host->pdata->core, GLAMO_ENGINE_MMC);*/ + host->clk_enabled = 0; + printk("clk disabled\n"); + } +} + +static void glamo_mci_clock_enable(struct glamo_mci_host *host) { + del_timer_sync(&host->disable_timer); + + if (!host->clk_enabled) { + glamo_engine_div_enable(host->pdata->core, GLAMO_ENGINE_MMC); + host->clk_enabled = 1; + printk("clk enabled\n"); + } +} + +static void glamo_mci_disable_timer(unsigned long data) { + struct glamo_mci_host *host = (struct glamo_mci_host *)data; + glamo_mci_clock_disable(host); +} + + +static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data) { struct scatterlist *sg; u16 __iomem *from_ptr = host->data_base; - struct mmc_data *data = host->mrq->data; void *sg_pointer; dev_dbg(&host->pdev->dev, "pio_read():\n"); @@ -159,14 +179,13 @@ static void do_pio_read(struct glamo_mci_host *host) } dev_dbg(&host->pdev->dev, "pio_read(): " - "complete (no more data).\n"); + "complete (no more data).\n"); } -static void do_pio_write(struct glamo_mci_host *host) +static void do_pio_write(struct glamo_mci_host *host, struct mmc_data *data) { struct scatterlist *sg; u16 __iomem *to_ptr = host->data_base; - struct mmc_data *data = host->mrq->data; void *sg_pointer; dev_dbg(&host->pdev->dev, "pio_write():\n"); @@ -182,117 +201,41 @@ static void do_pio_write(struct glamo_mci_host *host) dev_dbg(&host->pdev->dev, "pio_write(): complete\n"); } -static void glamo_mci_fix_card_div(struct glamo_mci_host *host, int div) -{ - unsigned long flags; - - spin_lock_irqsave(&host->pdata->core->lock, flags); - - if (div < 0) { - /* stop clock - remove clock from divider input */ - writew(readw(host->pdata->core->base + - GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK), - host->pdata->core->base + GLAMO_REG_CLOCK_GEN5_1); - } else { - - if (host->force_slow_during_powerup) - div = host->clk_rate / sd_post_power_clock; - else if (host->pdata->glamo_mmc_use_slow && - host->pdata->glamo_mmc_use_slow()) - div = div * sd_slow_ratio; - - if (div > 255) - div = 255; - /* - * set the nearest prescaler factor - * - * register shared with SCLK divisor -- no chance of race because - * we don't use sensor interface - */ - writew((readw(host->pdata->core->base + - GLAMO_REG_CLOCK_GEN8) & 0xff00) | div, - host->pdata->core->base + GLAMO_REG_CLOCK_GEN8); - /* enable clock to divider input */ - writew(readw(host->pdata->core->base + - GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK, - host->pdata->core->base + GLAMO_REG_CLOCK_GEN5_1); - } - spin_unlock_irqrestore(&host->pdata->core->lock, flags); - mdelay(5); -} - static int glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq) { - int div = 0; int real_rate = 0; if (freq) { - /* Set clock */ - for (div = 0; div < 255; div++) { - real_rate = host->clk_rate / (div + 1); - if (real_rate <= freq) - break; - } - - host->clk_div = div; - glamo_mci_fix_card_div(host, div); + glamo_mci_clock_enable(host); + real_rate = glamo_engine_reclock(host->pdata->core, GLAMO_ENGINE_MMC, freq); } else { - /* stop clock */ - host->clk_div = 0xff; - - if (!sd_idleclk && !host->force_slow_during_powerup) - /* clock off */ - glamo_mci_fix_card_div(host, -1); + glamo_mci_clock_disable(host); } - host->real_rate = real_rate; + return real_rate; } +static void glamo_mci_request_done(struct glamo_mci_host *host, struct +mmc_request *mrq) { + mod_timer(&host->disable_timer, jiffies + HZ / 16); -static void glamo_mci_irq_worker(struct work_struct *work) -{ - struct glamo_mci_host *host = - container_of(work, struct glamo_mci_host, irq_work); - struct mmc_command *cmd = host->mrq->cmd; - - if (cmd->data->flags & MMC_DATA_READ) { - do_pio_read(host); - } - - /* issue STOP if we have been given one to use */ - if (host->mrq->stop) { - glamo_mci_send_command(host, host->mrq->stop); - } - - if (!sd_idleclk && !host->force_slow_during_powerup) - /* clock off */ - glamo_mci_fix_card_div(host, -1); - - host->mrq = NULL; - mmc_request_done(host->mmc, cmd->mrq); + mmc_request_done(host->mmc, mrq); } -static irqreturn_t glamo_mci_irq(int irq, void *devid) + +static void glamo_mci_irq_worker(struct work_struct *work) { - struct glamo_mci_host *host = (struct glamo_mci_host*)devid; - u16 status; + struct glamo_mci_host *host = container_of(work, struct glamo_mci_host, + irq_work); struct mmc_command *cmd; - unsigned long flags; + uint16_t status; - if (host->suspending) { /* bad news, dangerous time */ - dev_err(&host->pdev->dev, "****glamo_mci_irq before resumed\n"); - goto leave; - } + if (!host->mrq || !host->mrq->cmd) + return; - if (!host->mrq) - goto leave; cmd = host->mrq->cmd; - if (!cmd) - goto leave; - - spin_lock_irqsave(&host->lock, flags); - status = readw(host->mmio_base + GLAMO_REG_MMC_RB_STAT1); + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); dev_dbg(&host->pdev->dev, "status = 0x%04x\n", status); /* we ignore a data timeout report if we are also told the data came */ @@ -300,36 +243,34 @@ static irqreturn_t glamo_mci_irq(int irq, void *devid) status &= ~GLAMO_STAT1_MMC_DTOUT; if (status & (GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT)) + GLAMO_STAT1_MMC_DTOUT)) cmd->error = -ETIMEDOUT; if (status & (GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)) + GLAMO_STAT1_MMC_BRERR)) cmd->error = -EILSEQ; if (cmd->error) { dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); goto done; } - /* - * disable the initial slow start after first bulk transfer - */ - if (host->force_slow_during_powerup) - host->force_slow_during_powerup--; - - /* - * we perform the memcpy out of Glamo memory outside of IRQ context - * so we don't block other interrupts - */ - schedule_work(&host->irq_work); + /* issue STOP if we have been given one to use */ + if (host->mrq->stop) + glamo_mci_send_command(host, host->mrq->stop); - goto unlock; + if (cmd->data->flags & MMC_DATA_READ) + do_pio_read(host, cmd->data); done: host->mrq = NULL; - mmc_request_done(host->mmc, cmd->mrq); -unlock: - spin_unlock_irqrestore(&host->lock, flags); -leave: + glamo_mci_request_done(host, cmd->mrq); +} + +static irqreturn_t glamo_mci_irq(int irq, void *devid) +{ + struct glamo_mci_host *host = (struct glamo_mci_host*)devid; + + schedule_work(&host->irq_work); + return IRQ_HANDLED; } @@ -341,13 +282,12 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, unsigned int timeout = 1000000; u16 * reg_resp = (u16 *)(host->mmio_base + GLAMO_REG_MMC_CMD_RSP1); u16 status; + int triggers_int = 1; /* if we can't do it, reject as busy */ - if (!readw(host->mmio_base + GLAMO_REG_MMC_RB_STAT1) & - GLAMO_STAT1_MMC_IDLE) { - host->mrq = NULL; + if (!glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1) & + GLAMO_STAT1_MMC_IDLE) { cmd->error = -EBUSY; - mmc_request_done(host->mmc, host->mrq); return; } @@ -360,9 +300,9 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, u8a[5] = (crc7(0, u8a, 5) << 1) | 0x01; /* crc7 on first 5 bytes of packet */ /* issue the wire-order array including CRC in register order */ - writew((u8a[4] << 8) | u8a[5], host->mmio_base + GLAMO_REG_MMC_CMD_REG1); - writew((u8a[2] << 8) | u8a[3], host->mmio_base + GLAMO_REG_MMC_CMD_REG2); - writew((u8a[0] << 8) | u8a[1], host->mmio_base + GLAMO_REG_MMC_CMD_REG3); + glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG1, ((u8a[4] << 8) | u8a[5])); + glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG2, ((u8a[2] << 8) | u8a[3])); + glamo_reg_write(host, GLAMO_REG_MMC_CMD_REG3, ((u8a[0] << 8) | u8a[1])); /* command index toggle */ fire |= (host->request_counter & 1) << 12; @@ -440,27 +380,36 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, /* multiblock with stop */ fire |= GLAMO_FIRE_MMC_CC_MBWS; else - /* multiblock NO stop-- 'RESERVED'? */ + /* multiblock NO stop-- 'RESERVED'? */ fire |= GLAMO_FIRE_MMC_CC_MBWNS; break; case MMC_STOP_TRANSMISSION: fire |= GLAMO_FIRE_MMC_CC_STOP; /* STOP */ + triggers_int = 0; break; default: fire |= GLAMO_FIRE_MMC_CC_BASIC; /* "basic command" */ + triggers_int = 0; break; } + + if (triggers_int) + host->mrq = cmd->mrq; + /* always largest timeout */ - writew(0xfff, host->mmio_base + GLAMO_REG_MMC_TIMEOUT); + glamo_reg_write(host, GLAMO_REG_MMC_TIMEOUT, 0xfff); /* Generate interrupt on txfer */ - glamo_reg_set_bit_mask(host, GLAMO_REG_MMC_BASIC, ~0x3e, - 0x0800 | GLAMO_BASIC_MMC_NO_CLK_RD_WAIT | - GLAMO_BASIC_MMC_EN_COMPL_INT | (sd_drive << 6)); + glamo_reg_set_bit_mask(host, GLAMO_REG_MMC_BASIC, 0xff36, + 0x0800 | + GLAMO_BASIC_MMC_NO_CLK_RD_WAIT | + GLAMO_BASIC_MMC_EN_COMPL_INT | + GLAMO_BASIC_MMC_EN_DATA_PUPS | + GLAMO_BASIC_MMC_EN_CMD_PUP); /* send the command out on the wire */ /* dev_info(&host->pdev->dev, "Using FIRE %04X\n", fire); */ - writew(fire, host->mmio_base + GLAMO_REG_MMC_CMD_FIRE); + glamo_reg_write(host, GLAMO_REG_MMC_CMD_FIRE, fire); /* we are deselecting card? because it isn't going to ack then... */ if ((cmd->opcode == 7) && (cmd->arg == 0)) @@ -470,15 +419,14 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, * we must spin until response is ready or timed out * -- we don't get interrupts unless there is a bulk rx */ - udelay(5); do - status = readw(host->mmio_base + GLAMO_REG_MMC_RB_STAT1); + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); while (((((status >> 15) & 1) != (host->request_counter & 1)) || (!(status & (GLAMO_STAT1_MMC_RB_RRDY | - GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT | - GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)))) && (timeout--)); + GLAMO_STAT1_MMC_RTOUT | + GLAMO_STAT1_MMC_DTOUT | + GLAMO_STAT1_MMC_BWERR | + GLAMO_STAT1_MMC_BRERR)))) && (timeout--)); if ((status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) || @@ -492,17 +440,17 @@ static void glamo_mci_send_command(struct glamo_mci_host *host, if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { cmd->resp[3] = readw(®_resp[0]) | - (readw(®_resp[1]) << 16); + (readw(®_resp[1]) << 16); cmd->resp[2] = readw(®_resp[2]) | - (readw(®_resp[3]) << 16); + (readw(®_resp[3]) << 16); cmd->resp[1] = readw(®_resp[4]) | - (readw(®_resp[5]) << 16); + (readw(®_resp[5]) << 16); cmd->resp[0] = readw(®_resp[6]) | - (readw(®_resp[7]) << 16); + (readw(®_resp[7]) << 16); } else { cmd->resp[0] = (readw(®_resp[0]) >> 8) | - (readw(®_resp[1]) << 8) | - ((readw(®_resp[2])) << 24); + (readw(®_resp[1]) << 8) | + ((readw(®_resp[2])) << 24); } } } @@ -511,28 +459,63 @@ static int glamo_mci_prepare_pio(struct glamo_mci_host *host, struct mmc_data *data) { /* set up the block info */ - writew(data->blksz, host->mmio_base + GLAMO_REG_MMC_DATBLKLEN); - writew(data->blocks, host->mmio_base + GLAMO_REG_MMC_DATBLKCNT); - dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n", - data->blksz, data->blocks); + glamo_reg_write(host, GLAMO_REG_MMC_DATBLKLEN, data->blksz); + glamo_reg_write(host, GLAMO_REG_MMC_DATBLKCNT, data->blocks); + data->bytes_xfered = 0; /* if write, prep the write into the shared RAM before the command */ if (data->flags & MMC_DATA_WRITE) { - do_pio_write(host); + do_pio_write(host, data); + } + + dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n", + data->blksz, data->blocks); + return 0; +} + +static int glamo_mci_irq_poll(struct glamo_mci_host *host, + struct mmc_command *cmd) +{ + int timeout = 1000000; + /* + * if the glamo INT# line isn't wired (*cough* it can happen) + * I'm afraid we have to spin on the IRQ status bit and "be + * our own INT# line" + */ + /* + * we have faith we will get an "interrupt"... + * but something insane like suspend problems can mean + * we spin here forever, so we timeout after a LONG time + */ + while ((!(readw(host->pdata->core->base + + GLAMO_REG_IRQ_STATUS) & GLAMO_IRQ_MMC)) && + (timeout--)); + + if (timeout < 0) { + if (cmd->data->error) + cmd->data->error = -ETIMEDOUT; + dev_err(&host->pdev->dev, "Payload timeout\n"); + return -ETIMEDOUT; } + /* ack this interrupt source */ + writew(GLAMO_IRQ_MMC, host->pdata->core->base + + GLAMO_REG_IRQ_CLEAR); + + /* yay we are an interrupt controller! -- call the ISR + * it will stop clock to card + */ + glamo_mci_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); + return 0; } -static void glamo_mci_send_request(struct mmc_host *mmc) +static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct glamo_mci_host *host = mmc_priv(mmc); - struct mmc_request *mrq = host->mrq; struct mmc_command *cmd = mrq->cmd; - int timeout = 1000000; host->request_counter++; - /* this guy has data to read/write? */ if (cmd->data) { if(glamo_mci_prepare_pio(host, cmd->data)) { cmd->data->error = -EIO; @@ -545,11 +528,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc) cmd->opcode, cmd->arg, cmd->data, cmd->mrq->stop, cmd->flags); - /* resume requested clock rate - * scale it down by sd_slow_ratio if platform requests it - */ - glamo_mci_fix_card_div(host, host->clk_div); - + glamo_mci_clock_enable(host); glamo_mci_send_command(host, cmd); /* @@ -558,6 +537,12 @@ static void glamo_mci_send_request(struct mmc_host *mmc) if (!cmd->data || cmd->error) goto done; + + if (!host->pdata->core->irq_works) { + if (glamo_mci_irq_poll(host, mrq->cmd)) + goto done; + } + /* * Otherwise can can use the interrupt as async completion -- * if there is read data coming, or we wait for write data to complete, @@ -565,95 +550,30 @@ static void glamo_mci_send_request(struct mmc_host *mmc) * will service it */ dev_dbg(&host->pdev->dev, "Waiting for payload data\n"); - /* - * if the glamo INT# line isn't wired (*cough* it can happen) - * I'm afraid we have to spin on the IRQ status bit and "be - * our own INT# line" - */ - if (!host->pdata->core->irq_works) { - /* - * we have faith we will get an "interrupt"... - * but something insane like suspend problems can mean - * we spin here forever, so we timeout after a LONG time - */ - while ((!(readw(host->pdata->core->base + - GLAMO_REG_IRQ_STATUS) & GLAMO_IRQ_MMC)) && - (timeout--)); - - if (timeout < 0) { - if (cmd->data->error) - cmd->data->error = -ETIMEDOUT; - dev_err(&host->pdev->dev, "Payload timeout\n"); - goto bail; - } - /* ack this interrupt source */ - writew(GLAMO_IRQ_MMC, host->pdata->core->base + - GLAMO_REG_IRQ_CLEAR); - - /* yay we are an interrupt controller! -- call the ISR - * it will stop clock to card - */ - glamo_mci_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); - } return; done: - host->mrq = NULL; - mmc_request_done(host->mmc, cmd->mrq); -bail: - if (!sd_idleclk && !host->force_slow_during_powerup) - /* stop the clock to card */ - glamo_mci_fix_card_div(host, -1); + glamo_mci_request_done(host, mrq); } -static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct glamo_mci_host *host = mmc_priv(mmc); - - host->mrq = mrq; - glamo_mci_send_request(mmc); -} - -static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct glamo_mci_host *host = mmc_priv(mmc); - int bus_width = 0; - int powering = 0; +static void glamo_mci_set_power_mode(struct glamo_mci_host *host, + unsigned char power_mode) { int ret; - if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_set_ios while " - "suspended\n"); + if (power_mode == host->power_mode) return; - } - /* Set power */ - switch(ios->power_mode) { + switch(power_mode) { case MMC_POWER_UP: - ret = regulator_enable(host->regulator); - if (ret) - dev_err(&host->pdev->dev, "Failed to enable regulator: %d\n", ret); + if (host->power_mode == MMC_POWER_OFF) { + ret = regulator_enable(host->regulator); + if (ret) + dev_err(&host->pdev->dev, "Failed to enable regulator: %d\n", ret); + } break; case MMC_POWER_ON: - /* - * we should use very slow clock until first bulk - * transfer completes OK - */ - host->force_slow_during_powerup = 1; - - if (host->power_mode_current == MMC_POWER_OFF) { - glamo_engine_enable(host->pdata->core, - GLAMO_ENGINE_MMC); - powering = 1; - } break; - case MMC_POWER_OFF: default: - if (host->power_mode_current == MMC_POWER_OFF) - break; - /* never want clocking with dead card */ - glamo_mci_fix_card_div(host, -1); - glamo_engine_disable(host->pdata->core, GLAMO_ENGINE_MMC); @@ -662,44 +582,50 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_warn(&host->pdev->dev, "Failed to disable regulator: %d\n", ret); break; } - host->power_mode_current = ios->power_mode; + host->power_mode = power_mode; +} - if (host->vdd_current != ios->vdd) { +static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct glamo_mci_host *host = mmc_priv(mmc); + int bus_width = 0; + int rate; + int sd_drive; + int ret; + + /* Set power */ + glamo_mci_set_power_mode(host, ios->power_mode); + + if (host->vdd != ios->vdd) { ret = mmc_regulator_set_ocr(host->regulator, ios->vdd); if (ret) dev_err(&host->pdev->dev, "Failed to set regulator voltage: %d\n", ret); else - host->vdd_current = ios->vdd; + host->vdd = ios->vdd; } - glamo_mci_set_card_clock(host, ios->clock); - - /* after power-up, we are meant to give it >= 74 clocks so it can - * initialize itself. Doubt any modern cards need it but anyway... - */ - if (powering) - mdelay(1); - - if (!sd_idleclk && !host->force_slow_during_powerup) - /* stop the clock to card, because we are idle until transfer */ - glamo_mci_fix_card_div(host, -1); + rate = glamo_mci_set_card_clock(host, ios->clock); if ((ios->power_mode == MMC_POWER_ON) || (ios->power_mode == MMC_POWER_UP)) { dev_info(&host->pdev->dev, - "powered (vdd = %d) clk: %lukHz div=%d (req: %ukHz). " - "Bus width=%d\n",(int)ios->vdd, - host->real_rate / 1000, (int)host->clk_div, + "powered (vdd = %hu) clk: %dkHz div=%hu (req: %ukHz). " + "Bus width=%d\n", ios->vdd, + rate / 1000, 0, ios->clock / 1000, (int)ios->bus_width); - } else + } else { dev_info(&host->pdev->dev, "glamo_mci_set_ios: power down.\n"); + } /* set bus width */ if (ios->bus_width == MMC_BUS_WIDTH_4) bus_width = GLAMO_BASIC_MMC_EN_4BIT_DATA; + + sd_drive = (rate * 4) / host->clk_rate; + if (sd_drive > 3) + sd_drive = 3; + glamo_reg_set_bit_mask(host, GLAMO_REG_MMC_BASIC, - GLAMO_BASIC_MMC_EN_4BIT_DATA | - GLAMO_BASIC_MMC_EN_DR_STR0 | - GLAMO_BASIC_MMC_EN_DR_STR1, + GLAMO_BASIC_MMC_EN_4BIT_DATA | 0xb0, bus_width | sd_drive << 6); } @@ -713,7 +639,7 @@ static int glamo_mci_get_ro(struct mmc_host *mmc) } static struct mmc_host_ops glamo_mci_ops = { - .request = glamo_mci_request, + .request = glamo_mci_send_request, .set_ios = glamo_mci_set_ios, .get_ro = glamo_mci_get_ro, }; @@ -736,9 +662,9 @@ static int glamo_mci_probe(struct platform_device *pdev) host->mmc = mmc; host->pdev = pdev; host->pdata = pdev->dev.platform_data; - host->power_mode_current = MMC_POWER_OFF; + host->power_mode = MMC_POWER_OFF; + host->clk_enabled = 0; - spin_lock_init(&host->lock); INIT_WORK(&host->irq_work, glamo_mci_irq_worker); host->regulator = regulator_get(pdev->dev.parent, "SD_3V3"); @@ -810,9 +736,8 @@ static int glamo_mci_probe(struct platform_device *pdev) } - host->vdd_current = 0; - host->clk_rate = 50000000; /* really it's 49152000 */ - host->clk_div = 16; + host->vdd = 0; + host->clk_rate = glamo_pll_rate(host->pdata->core, GLAMO_PLL1); /* explain our host controller capabilities */ mmc->ops = &glamo_mci_ops; @@ -821,7 +746,7 @@ static int glamo_mci_probe(struct platform_device *pdev) MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; mmc->f_min = host->clk_rate / 256; - mmc->f_max = sd_max_clk; + mmc->f_max = host->clk_rate; mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */ mmc->max_blk_size = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */ @@ -841,21 +766,24 @@ static int glamo_mci_probe(struct platform_device *pdev) glamo_engine_enable(host->pdata->core, GLAMO_ENGINE_MMC); glamo_engine_reset(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_reg_write(host, GLAMO_REG_MMC_WDATADS1, + (u16)(host->data_mem->start)); + glamo_reg_write(host, GLAMO_REG_MMC_WDATADS2, + (u16)(host->data_mem->start >> 16)); + + glamo_reg_write(host, GLAMO_REG_MMC_RDATADS1, + (u16)(host->data_mem->start)); + glamo_reg_write(host, GLAMO_REG_MMC_RDATADS2, + (u16)(host->data_mem->start >> 16)); + + setup_timer(&host->disable_timer, glamo_mci_disable_timer, + (unsigned long)host); + if ((ret = mmc_add_host(mmc))) { dev_err(&pdev->dev, "failed to add mmc host.\n"); goto probe_freeirq; } - writew((u16)(host->data_mem->start), - host->mmio_base + GLAMO_REG_MMC_WDATADS1); - writew((u16)((host->data_mem->start) >> 16), - host->mmio_base + GLAMO_REG_MMC_WDATADS2); - - writew((u16)host->data_mem->start, host->mmio_base + - GLAMO_REG_MMC_RDATADS1); - writew((u16)(host->data_mem->start >> 16), host->mmio_base + - GLAMO_REG_MMC_RDATADS2); - dev_info(&pdev->dev,"initialisation done.\n"); return 0; @@ -904,51 +832,41 @@ static int glamo_mci_remove(struct platform_device *pdev) static int glamo_mci_suspend(struct platform_device *dev, pm_message_t state) { struct mmc_host *mmc = platform_get_drvdata(dev); - struct glamo_mci_host *host = mmc_priv(mmc); + struct glamo_mci_host *host = mmc_priv(mmc); int ret; cancel_work_sync(&host->irq_work); - /* - * possible workaround for SD corruption during suspend - resume - * make sure the clock was running during suspend and consequently - * resume - */ - glamo_mci_fix_card_div(host, host->clk_div); - - /* we are going to do more commands to override this in - * mmc_suspend_host(), so we need to change sd_idleclk for the - * duration as well - */ - suspend_sd_idleclk = sd_idleclk; - sd_idleclk = 1; - ret = mmc_suspend_host(mmc, state); - - host->suspending++; + glamo_mci_clock_enable(host); return ret; } -int glamo_mci_resume(struct platform_device *dev) +static int glamo_mci_resume(struct platform_device *dev) { struct mmc_host *mmc = platform_get_drvdata(dev); - struct glamo_mci_host *host = mmc_priv(mmc); + struct glamo_mci_host *host = mmc_priv(mmc); int ret; - sd_idleclk = 1; + glamo_engine_enable(host->pdata->core, GLAMO_ENGINE_MMC); + glamo_engine_reset(host->pdata->core, GLAMO_ENGINE_MMC); - glamo_engine_enable(host->pdata->core, GLAMO_ENGINE_MMC); - glamo_engine_reset(host->pdata->core, GLAMO_ENGINE_MMC); - - host->suspending--; + glamo_reg_write(host, GLAMO_REG_MMC_WDATADS1, + (u16)(host->data_mem->start)); + glamo_reg_write(host, GLAMO_REG_MMC_WDATADS2, + (u16)(host->data_mem->start >> 16)); - ret = mmc_resume_host(mmc); + glamo_reg_write(host, GLAMO_REG_MMC_RDATADS1, + (u16)(host->data_mem->start)); + glamo_reg_write(host, GLAMO_REG_MMC_RDATADS2, + (u16)(host->data_mem->start >> 16)); + mdelay(5); - /* put sd_idleclk back to pre-suspend state */ - sd_idleclk = suspend_sd_idleclk; + ret = mmc_resume_host(host->mmc); +/* glamo_mci_clock_disable(host);*/ - return ret; + return 0; } EXPORT_SYMBOL_GPL(glamo_mci_resume); diff --git a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.h b/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.h deleted file mode 100644 index 52c3fe3342..0000000000 --- a/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * linux/drivers/mmc/host/glamo-mmc.h - GLAMO MCI driver - * - * Copyright (C) 2007-2008 Openmoko, Inc, Andy Green <andy@openmoko.com> - * based on S3C MMC driver --> - * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/regulator/consumer.h> - -struct glamo_mci_host { - struct platform_device *pdev; - struct glamo_mmc_platform_data *pdata; - struct mmc_host *mmc; - struct resource *mmio_mem; - struct resource *data_mem; - void __iomem *mmio_base; - u16 __iomem *data_base; - - int suspending; - - int power_mode_current; - unsigned int vdd_current; - - unsigned long clk_rate; - unsigned long clk_div; - unsigned long real_rate; - - int force_slow_during_powerup; - - struct mmc_request *mrq; - struct work_struct irq_work; - - spinlock_t lock; - - unsigned int request_counter; - - struct regulator *regulator; -}; |