X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/fb189822fcab111e55d1c7e83c482dc2c144500a..08d7f245afef278594ba85a6e1184681da4e8835:/target/linux/s3c24xx/files-2.6.30/drivers/mfd/glamo/glamo-mci.c 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 956be5717..b728c8745 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 @@ -11,34 +11,57 @@ */ #include -#include -#include #include +#include #include #include #include #include #include -#include #include +#include +#include +#include +#include +#include -#include -#include -#include - -#include "glamo-mci.h" #include "glamo-core.h" #include "glamo-regs.h" -/* from glamo-core.c */ -extern struct glamo_mci_pdata glamo_mci_def_pdata; +#define DRIVER_NAME "glamo-mci" -static spinlock_t clock_lock; +struct glamo_mci_host { + struct glamo_mmc_platform_data *pdata; + struct platform_device *pdev; + struct glamo_core *core; + struct mmc_host *mmc; + struct resource *mmio_mem; + struct resource *data_mem; + void __iomem *mmio_base; + u16 __iomem *data_base; -#define DRIVER_NAME "glamo-mci" -#define RESSIZE(ressource) (((ressource)->end - (ressource)->start) + 1) + struct regulator *regulator; + struct mmc_request *mrq; + + unsigned int clk_rate; -static void glamo_mci_send_request(struct mmc_host *mmc); + unsigned short vdd; + char power_mode; + + unsigned char request_counter; + + struct timer_list disable_timer; + + struct work_struct irq_work; + struct work_struct read_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); /* * Max SD clock rate @@ -53,7 +76,7 @@ static void glamo_mci_send_request(struct mmc_host *mmc); * for example */ -static int sd_max_clk = 50000000 / 3; +static int sd_max_clk = 21000000; module_param(sd_max_clk, int, 0644); /* @@ -90,362 +113,246 @@ 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; - - -unsigned char CRC7(u8 * pu8, int cnt) +static inline void glamo_reg_write(struct glamo_mci_host *glamo, + u_int16_t reg, u_int16_t val) { - u8 crc = 0; - - while (cnt--) { - int n; - u8 d = *pu8++; - for (n = 0; n < 8; n++) { - crc <<= 1; - if ((d & 0x80) ^ (crc & 0x80)) - crc ^= 0x09; - d <<= 1; - } - } - return (crc << 1) | 1; + writew(val, glamo->mmio_base + reg); } -static int get_data_buffer(struct glamo_mci_host *host, - volatile u32 *words, volatile u16 **pointer) +static inline u_int16_t glamo_reg_read(struct glamo_mci_host *glamo, + u_int16_t reg) { - struct scatterlist *sg; + return readw(glamo->mmio_base + reg); +} - *words = 0; - *pointer = NULL; +static void glamo_reg_set_bit_mask(struct glamo_mci_host *glamo, + u_int16_t reg, u_int16_t mask, + u_int16_t val) +{ + u_int16_t tmp; - if (host->pio_active == XFER_NONE) - return -EINVAL; + val &= mask; - if ((!host->mrq) || (!host->mrq->data)) - return -EINVAL; + tmp = glamo_reg_read(glamo, reg); + tmp &= ~mask; + tmp |= val; + glamo_reg_write(glamo, reg, tmp); +} - if (host->pio_sgptr >= host->mrq->data->sg_len) { - dev_dbg(&host->pdev->dev, "no more buffers (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); - return -EBUSY; +static void glamo_mci_clock_disable(struct glamo_mci_host *host) { + if (host->clk_enabled) { + glamo_engine_div_disable(host->core, GLAMO_ENGINE_MMC); + host->clk_enabled = 0; } - sg = &host->mrq->data->sg[host->pio_sgptr]; - - *words = sg->length >> 1; /* we are working with a 16-bit data bus */ - *pointer = page_address(sg_page(sg)) + sg->offset; - - BUG_ON(((long)(*pointer)) & 1); +} - host->pio_sgptr++; +static void glamo_mci_clock_enable(struct glamo_mci_host *host) { + del_timer_sync(&host->disable_timer); - /* dev_info(&host->pdev->dev, "new buffer (%i/%i)\n", - host->pio_sgptr, host->mrq->data->sg_len); */ - return 0; + if (!host->clk_enabled) { + glamo_engine_div_enable(host->core, GLAMO_ENGINE_MMC); + host->clk_enabled = 1; + } } -static void do_pio_read(struct glamo_mci_host *host) -{ - int res; - u16 __iomem *from_ptr = host->base_data + (RESSIZE(host->mem_data) / - sizeof(u16) / 2); -#ifdef DEBUG - u16 * block; -#endif +static void glamo_mci_disable_timer(unsigned long data) { + struct glamo_mci_host *host = (struct glamo_mci_host *)data; + glamo_mci_clock_disable(host); +} - while (1) { - res = get_data_buffer(host, &host->pio_words, &host->pio_ptr); - if (res) { - host->pio_active = XFER_NONE; - host->complete_what = COMPLETION_FINALIZE; - dev_dbg(&host->pdev->dev, "pio_read(): " - "complete (no more data).\n"); - return; - } +static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data) +{ + struct scatterlist *sg; + u16 __iomem *from_ptr = host->data_base; + void *sg_pointer; - dev_dbg(&host->pdev->dev, "pio_read(): host->pio_words: %d\n", - host->pio_words); + dev_dbg(&host->pdev->dev, "pio_read():\n"); + for (sg = data->sg; sg; sg = sg_next(sg)) { + sg_pointer = page_address(sg_page(sg)) + sg->offset; - host->pio_count += host->pio_words << 1; -#ifdef DEBUG - block = (u16 *)host->pio_ptr; - res = host->pio_words << 1; -#endif -#if 0 - /* u16-centric memcpy */ - while (host->pio_words--) - *host->pio_ptr++ = *from_ptr++; -#else - /* memcpy can be faster? */ - memcpy((void *)host->pio_ptr, from_ptr, host->pio_words << 1); - host->pio_ptr += host->pio_words; -#endif + memcpy(sg_pointer, from_ptr, sg->length); + from_ptr += sg->length >> 1; -#ifdef DEBUG - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, - (void *)block, res, 1); -#endif + data->bytes_xfered += sg->length; } + + dev_dbg(&host->pdev->dev, "pio_read(): " + "complete (no more data).\n"); } -static int do_pio_write(struct glamo_mci_host *host) +static void do_pio_write(struct glamo_mci_host *host, struct mmc_data *data) { - int res = 0; - volatile u16 __iomem *to_ptr = host->base_data; - int err = 0; + struct scatterlist *sg; + u16 __iomem *to_ptr = host->data_base; + void *sg_pointer; dev_dbg(&host->pdev->dev, "pio_write():\n"); - while (!res) { - res = get_data_buffer(host, &host->pio_words, &host->pio_ptr); - if (res) - continue; + for (sg = data->sg; sg; sg = sg_next(sg)) { + sg_pointer = page_address(sg_page(sg)) + sg->offset; - dev_dbg(&host->pdev->dev, "pio_write():new source: [%i]@[%p]\n", - host->pio_words, host->pio_ptr); + data->bytes_xfered += sg->length; - host->pio_count += host->pio_words << 1; - while (host->pio_words--) - writew(*host->pio_ptr++, to_ptr++); + memcpy(to_ptr, sg_pointer, sg->length); + to_ptr += sg->length >> 1; } dev_dbg(&host->pdev->dev, "pio_write(): complete\n"); - host->pio_active = XFER_NONE; - return err; -} - -static void __glamo_mci_fix_card_div(struct glamo_mci_host *host, int div) -{ - unsigned long flags; - - spin_lock_irqsave(&clock_lock, flags); - - if (div < 0) { - /* stop clock - remove clock from divider input */ - writew(readw(glamo_mci_def_pdata.pglamo->base + - GLAMO_REG_CLOCK_GEN5_1) & (~GLAMO_CLOCK_GEN51_EN_DIV_TCLK), - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1); - - goto done; - } else { - /* set the nearest prescaler factor - * - * register shared with SCLK divisor -- no chance of race because - * we don't use sensor interface - */ - writew((readw(glamo_mci_def_pdata.pglamo->base + - GLAMO_REG_CLOCK_GEN8) & 0xff00) | div, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8); - /* enable clock to divider input */ - writew(readw(glamo_mci_def_pdata.pglamo->base + - GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1); - } - - if (host->force_slow_during_powerup) - div = host->clk_rate / sd_post_power_clock; - else - if (host->pdata->glamo_mci_use_slow) - if ((host->pdata->glamo_mci_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(glamo_mci_def_pdata.pglamo->base + - GLAMO_REG_CLOCK_GEN8) & 0xff00) | div, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN8); - /* enable clock to divider input */ - writew(readw(glamo_mci_def_pdata.pglamo->base + - GLAMO_REG_CLOCK_GEN5_1) | GLAMO_CLOCK_GEN51_EN_DIV_TCLK, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_GEN5_1); - -done: - spin_unlock_irqrestore(&clock_lock, flags); } -static int __glamo_mci_set_card_clock(struct glamo_mci_host *host, int freq, - int *division) +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 < 256; div++) { - real_rate = host->clk_rate / (div + 1); - if (real_rate <= freq) - break; - } - if (div > 255) - div = 255; - - if (division) - *division = div; - - __glamo_mci_fix_card_div(host, div); - + glamo_mci_clock_enable(host); + real_rate = glamo_engine_reclock(host->core, GLAMO_ENGINE_MMC, freq); } else { - /* stop clock */ - if (division) - *division = 0xff; - - if (!sd_idleclk && !host->force_slow_during_powerup) - /* clock off */ - __glamo_mci_fix_card_div(host, -1); + glamo_mci_clock_disable(host); } 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); + mmc_request_done(host->mmc, mrq); +} + 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; + struct glamo_mci_host *host = container_of(work, struct glamo_mci_host, + irq_work); + struct mmc_command *cmd; + uint16_t status; + if (!host->mrq || !host->mrq->cmd) + return; - if (host->pio_active == XFER_READ) - do_pio_read(host); + cmd = host->mrq->cmd; - host->mrq->data->bytes_xfered = host->pio_count; - dev_dbg(&host->pdev->dev, "count=%d\n", host->pio_count); +#if 0 + if (cmd->data->flags & MMC_DATA_READ) { + return; + } +#endif + + 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 */ + if (status & GLAMO_STAT1_MMC_RB_DRDY) + status &= ~GLAMO_STAT1_MMC_DTOUT; + + if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) + cmd->error = -ETIMEDOUT; + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) { + cmd->error = -EILSEQ; + } + if (cmd->error) { + dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); + goto done; + } /* issue STOP if we have been given one to use */ if (host->mrq->stop) { - host->cmd_is_stop = 1; - glamo_mci_send_request(host->mmc); - host->cmd_is_stop = 0; + 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); + if (cmd->data->flags & MMC_DATA_READ) + do_pio_read(host, cmd->data); - host->complete_what = COMPLETION_NONE; +done: host->mrq = NULL; - mmc_request_done(host->mmc, cmd->mrq); + glamo_mci_request_done(host, cmd->mrq); } -static void glamo_mci_irq_host(struct glamo_mci_host *host) +static void glamo_mci_read_worker(struct work_struct *work) { - u16 status; + struct glamo_mci_host *host = container_of(work, struct glamo_mci_host, + read_work); struct mmc_command *cmd; - unsigned long iflags; + uint16_t status; + uint16_t blocks_ready; + size_t data_read = 0; + size_t data_ready; + struct scatterlist *sg; + u16 __iomem *from_ptr = host->data_base; + void *sg_pointer; - if (host->suspending) { /* bad news, dangerous time */ - dev_err(&host->pdev->dev, "****glamo_mci_irq before resumed\n"); - return; - } - if (!host->mrq) - return; cmd = host->mrq->cmd; - if (!cmd) - return; + sg = cmd->data->sg; + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + + if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT)) + cmd->error = -ETIMEDOUT; + if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) + cmd->error = -EILSEQ; + if (cmd->error) { + dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); + goto done; + } - spin_lock_irqsave(&host->complete_lock, iflags); + blocks_ready = glamo_reg_read(host, GLAMO_REG_MMC_RB_BLKCNT); + data_ready = blocks_ready * cmd->data->blksz; - status = readw(host->base + GLAMO_REG_MMC_RB_STAT1); - dev_dbg(&host->pdev->dev, "status = 0x%04x\n", status); + if (data_ready == data_read) + yield(); - /* ack this interrupt source */ - writew(GLAMO_IRQ_MMC, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_IRQ_CLEAR); - - /* we ignore a data timeout report if we are also told the data came */ - if (status & GLAMO_STAT1_MMC_RB_DRDY) - status &= ~GLAMO_STAT1_MMC_DTOUT; + while(sg && data_read + sg->length <= data_ready) { + sg_pointer = page_address(sg_page(sg)) + sg->offset; + memcpy(sg_pointer, from_ptr, sg->length); + from_ptr += sg->length >> 1; - if (status & (GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT)) - cmd->error = -ETIMEDOUT; - if (status & (GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)) - cmd->error = -EILSEQ; - if (cmd->error) { - dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); - goto done; - } + data_read += sg->length; + sg = sg_next(sg); + } - /* - * disable the initial slow start after first bulk transfer - */ - if (host->force_slow_during_powerup) - host->force_slow_during_powerup--; + } while(sg); + cmd->data->bytes_xfered = data_read; - /* - * we perform the memcpy out of Glamo memory outside of IRQ context - * so we don't block other interrupts - */ - schedule_work(&host->irq_work); + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + } while (!(status & GLAMO_STAT1_MMC_IDLE)); - goto leave; + if (host->mrq->stop) + glamo_mci_send_command(host, host->mrq->stop); + do { + status = glamo_reg_read(host, GLAMO_REG_MMC_RB_STAT1); + } while (!(status & GLAMO_STAT1_MMC_IDLE)); done: - host->complete_what = COMPLETION_NONE; host->mrq = NULL; - mmc_request_done(host->mmc, cmd->mrq); -leave: - spin_unlock_irqrestore(&host->complete_lock, iflags); + glamo_mci_request_done(host, cmd->mrq); } -static void glamo_mci_irq(unsigned int irq, struct irq_desc *desc) +static irqreturn_t glamo_mci_irq(int irq, void *devid) { - struct glamo_mci_host *host = (struct glamo_mci_host *) - desc->handler_data; - - if (host) - glamo_mci_irq_host(host); + struct glamo_mci_host *host = (struct glamo_mci_host*)devid; + schedule_work(&host->irq_work); + return IRQ_HANDLED; } -static int glamo_mci_send_command(struct glamo_mci_host *host, +static void glamo_mci_send_command(struct glamo_mci_host *host, struct mmc_command *cmd) { u8 u8a[6]; u16 fire = 0; + 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->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 -EBUSY; + return; } /* create an array in wire order for CRC computation */ @@ -454,15 +361,15 @@ static int glamo_mci_send_command(struct glamo_mci_host *host, u8a[2] = (u8)(cmd->arg >> 16); u8a[3] = (u8)(cmd->arg >> 8); u8a[4] = (u8)cmd->arg; - u8a[5] = CRC7(&u8a[0], 5); /* CRC7 on first 5 bytes of packet */ + 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->base + GLAMO_REG_MMC_CMD_REG1); - writew((u8a[2] << 8) | u8a[3], host->base + GLAMO_REG_MMC_CMD_REG2); - writew((u8a[0] << 8) | u8a[1], host->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->ccnt & 1) << 12; + fire |= (host->request_counter & 1) << 12; /* set type of command */ switch (mmc_cmd_type(cmd)) { @@ -493,7 +400,7 @@ static int glamo_mci_send_command(struct glamo_mci_host *host, * check pattern, CRC7) */ switch (mmc_resp_type(cmd)) { - case MMC_RSP_R6: /* same index as R7 and R1 */ + case MMC_RSP_R1: /* same index as R6 and R7 */ fire |= GLAMO_FIRE_MMC_RSPT_R1; break; case MMC_RSP_R1B: @@ -519,7 +426,7 @@ static int glamo_mci_send_command(struct glamo_mci_host *host, fire |= GLAMO_FIRE_MMC_CC_SBR; /* single block read */ break; case MMC_SWITCH: /* 64 byte payload */ - case 0x33: /* observed issued by MCI */ + case SD_APP_SEND_SCR: case MMC_READ_MULTIPLE_BLOCK: /* we will get an interrupt off this */ if (!cmd->mrq->stop) @@ -537,112 +444,156 @@ static int 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 (cmd->data) + host->mrq = cmd->mrq; + /* always largest timeout */ - writew(0xfff, host->base + GLAMO_REG_MMC_TIMEOUT); + glamo_reg_write(host, GLAMO_REG_MMC_TIMEOUT, 0xfff); /* Generate interrupt on txfer */ - writew((readw(host->base + GLAMO_REG_MMC_BASIC) & 0x3e) | - 0x0800 | GLAMO_BASIC_MMC_NO_CLK_RD_WAIT | - GLAMO_BASIC_MMC_EN_COMPL_INT | (sd_drive << 6), - host->base + GLAMO_REG_MMC_BASIC); + 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->base + GLAMO_REG_MMC_CMD_FIRE); - cmd->error = 0; - return 0; -} + 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)) + return; -static int glamo_mci_prepare_pio(struct glamo_mci_host *host, - struct mmc_data *data) -{ /* - * the S-Media-internal RAM offset for our MMC buffer - * Read is halfway up the buffer and write is at the start + * we must spin until response is ready or timed out + * -- we don't get interrupts unless there is a bulk rx */ - if (data->flags & MMC_DATA_READ) { - writew((u16)(GLAMO_FB_SIZE + (RESSIZE(host->mem_data) / 2)), - host->base + GLAMO_REG_MMC_WDATADS1); - writew((u16)((GLAMO_FB_SIZE + - (RESSIZE(host->mem_data) / 2)) >> 16), - host->base + GLAMO_REG_MMC_WDATADS2); - } else { - writew((u16)GLAMO_FB_SIZE, host->base + - GLAMO_REG_MMC_RDATADS1); - writew((u16)(GLAMO_FB_SIZE >> 16), host->base + - GLAMO_REG_MMC_RDATADS2); + do + 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--)); + + if ((status & (GLAMO_STAT1_MMC_RTOUT | + GLAMO_STAT1_MMC_DTOUT)) || + (timeout == 0)) { + cmd->error = -ETIMEDOUT; + } else if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR)) { + cmd->error = -EILSEQ; } + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + cmd->resp[3] = readw(®_resp[0]) | + (readw(®_resp[1]) << 16); + cmd->resp[2] = readw(®_resp[2]) | + (readw(®_resp[3]) << 16); + cmd->resp[1] = readw(®_resp[4]) | + (readw(®_resp[5]) << 16); + cmd->resp[0] = readw(®_resp[6]) | + (readw(®_resp[7]) << 16); + } else { + cmd->resp[0] = (readw(®_resp[0]) >> 8) | + (readw(®_resp[1]) << 8) | + ((readw(®_resp[2])) << 24); + } + } + +#if 0 + /* We'll only get an interrupt when all data has been transfered. + By starting to copy data when it's avaiable we can increase throughput by + up to 30%. */ + if (cmd->data && (cmd->data->flags & MMC_DATA_READ)) + schedule_work(&host->read_work); +#endif + +} + +static int glamo_mci_prepare_pio(struct glamo_mci_host *host, + struct mmc_data *data) +{ /* set up the block info */ - writew(data->blksz, host->base + GLAMO_REG_MMC_DATBLKLEN); - writew(data->blocks, host->base + GLAMO_REG_MMC_DATBLKCNT); - dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n", - data->blksz, data->blocks); - host->pio_sgptr = 0; - host->pio_words = 0; - host->pio_count = 0; - host->pio_active = 0; + 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) { - host->pio_active = XFER_WRITE; - return do_pio_write(host); + do_pio_write(host, data); } - host->pio_active = XFER_READ; + + dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n", + data->blksz, data->blocks); return 0; } -static void glamo_mci_send_request(struct mmc_host *mmc) +static int glamo_mci_irq_poll(struct glamo_mci_host *host, + struct mmc_command *cmd) { - struct glamo_mci_host *host = mmc_priv(mmc); - struct mmc_request *mrq = host->mrq; - struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - u16 * pu16 = (u16 *)&cmd->resp[0]; - u16 * reg_resp = (u16 *)(host->base + GLAMO_REG_MMC_CMD_RSP1); - u16 status; - int n; int timeout = 1000000; - int insanity_timeout = 1000000; - - if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_send_request while " - "suspended\n"); - cmd->error = -EIO; - if (cmd->data) - cmd->data->error = -EIO; - mmc_request_done(mmc, mrq); - return; + /* + * 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->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->core->base + + GLAMO_REG_IRQ_CLEAR); - host->ccnt++; - /* - * somehow 2.6.24 MCI manages to issue MMC_WRITE_BLOCK *without* the - * MMC_DATA_WRITE flag, WTF? Work around the madness. + /* yay we are an interrupt controller! -- call the ISR + * it will stop clock to card */ - if (cmd->opcode == MMC_WRITE_BLOCK) - if (mrq->data) - mrq->data->flags |= MMC_DATA_WRITE; - - /* this guy has data to read/write? */ - if ((!host->cmd_is_stop) && cmd->data) { - int res; - host->dcnt++; - res = glamo_mci_prepare_pio(host, cmd->data); - if (res) { + glamo_mci_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); + + return 0; +} + +static void glamo_mci_send_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct glamo_mci_host *host = mmc_priv(mmc); + struct mmc_command *cmd = mrq->cmd; + + glamo_mci_clock_enable(host); + host->request_counter++; + if (cmd->data) { + if(glamo_mci_prepare_pio(host, cmd->data)) { cmd->error = -EIO; cmd->data->error = -EIO; - mmc_request_done(mmc, mrq); - return; + goto done; } } @@ -651,67 +602,19 @@ 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); - - if (glamo_mci_send_command(host, cmd)) - goto bail; - - /* we are deselecting card? because it isn't going to ack then... */ - if ((cmd->opcode == 7) && (cmd->arg == 0)) - goto done; + glamo_mci_send_command(host, cmd); /* - * we must spin until response is ready or timed out - * -- we don't get interrupts unless there is a bulk rx + * if we don't have bulk data to take care of, we're done */ - do - status = readw(host->base + GLAMO_REG_MMC_RB_STAT1); - while (((((status >> 15) & 1) != (host->ccnt & 1)) || - (!(status & (GLAMO_STAT1_MMC_RB_RRDY | - GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT | - GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)))) && (insanity_timeout--)); - - if (insanity_timeout < 0) - dev_info(&host->pdev->dev, "command timeout, continuing\n"); - - if (status & (GLAMO_STAT1_MMC_RTOUT | - GLAMO_STAT1_MMC_DTOUT)) - cmd->error = -ETIMEDOUT; - if (status & (GLAMO_STAT1_MMC_BWERR | - GLAMO_STAT1_MMC_BRERR)) - cmd->error = -EILSEQ; + if (!cmd->data || cmd->error) + goto done; - if (host->cmd_is_stop) - goto bail; - if (cmd->error) { - dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n", status); - goto done; + if (!host->core->irq_works) { + if (glamo_mci_irq_poll(host, mrq->cmd)) + goto done; } - /* - * mangle the response registers in two different exciting - * undocumented ways discovered by trial and error - */ - if (mmc_resp_type(cmd) == MMC_RSP_R2) - /* grab the response */ - for (n = 0; n < 8; n++) /* super mangle power 1 */ - pu16[n ^ 6] = readw(®_resp[n]); - else - for (n = 0; n < 3; n++) /* super mangle power 2 */ - pu16[n] = (readw(®_resp[n]) >> 8) | - (readw(®_resp[n + 1]) << 8); - /* - * if we don't have bulk data to take care of, we're done - */ - if (!cmd->data) - goto done; - if (!(cmd->data->flags & (MMC_DATA_READ | MMC_DATA_WRITE))) - goto done; /* * Otherwise can can use the interrupt as async completion -- @@ -720,182 +623,83 @@ 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 (!glamo_mci_def_pdata.pglamo->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(glamo_mci_def_pdata.pglamo->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; - } - - /* yay we are an interrupt controller! -- call the ISR - * it will stop clock to card - */ - glamo_mci_irq_host(host); - } return; - done: - host->complete_what = COMPLETION_NONE; - 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); -} - -static void glamo_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct glamo_mci_host *host = mmc_priv(mmc); - - host->cmd_is_stop = 0; - host->mrq = mrq; - glamo_mci_send_request(mmc); -} - -#if 1 -static void glamo_mci_reset(struct glamo_mci_host *host) -{ - if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_reset while " - "suspended\n"); - return; - } - dev_dbg(&host->pdev->dev, "******* glamo_mci_reset\n"); - /* reset MMC controller */ - writew(GLAMO_CLOCK_MMC_RESET | GLAMO_CLOCK_MMC_DG_TCLK | - GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK | - GLAMO_CLOCK_MMC_EN_M9CLK, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_MMC); - udelay(10); - /* and disable reset */ - writew(GLAMO_CLOCK_MMC_DG_TCLK | - GLAMO_CLOCK_MMC_EN_TCLK | GLAMO_CLOCK_MMC_DG_M9CLK | - GLAMO_CLOCK_MMC_EN_M9CLK, - glamo_mci_def_pdata.pglamo->base + GLAMO_REG_CLOCK_MMC); + glamo_mci_request_done(host, mrq); } -#endif -static inline int glamo_mci_get_mv(int vdd) -{ - int mv = 1650; - - if (vdd > 7) - mv += 350 + 100 * (vdd - 8); - return mv; -} +static void glamo_mci_set_power_mode(struct glamo_mci_host *host, + unsigned char power_mode) { + int ret; -static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct glamo_mci_host *host = mmc_priv(mmc); - struct regulator *regulator; - int n = 0; - int div; - int powering = 0; - int mv; - - if (host->suspending) { - dev_err(&host->pdev->dev, "IGNORING glamo_mci_set_ios while " - "suspended\n"); + if (power_mode == host->power_mode) return; - } - - regulator = host->regulator; - /* Set power */ - switch(ios->power_mode) { + switch(power_mode) { case MMC_POWER_UP: - if (host->pdata->glamo_can_set_mci_power()) { - mv = glamo_mci_get_mv(ios->vdd); - regulator_set_voltage(regulator, mv * 1000, mv * 1000); - regulator_enable(regulator); + 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->vdd_current != ios->vdd) { - if (host->pdata->glamo_can_set_mci_power()) { - mv = glamo_mci_get_mv(ios->vdd); - regulator_set_voltage(regulator, mv * 1000, mv * 1000); - printk(KERN_INFO "SD power -> %dmV\n", mv); - } - host->vdd_current = ios->vdd; - } - if (host->power_mode_current == MMC_POWER_OFF) { - glamo_engine_enable(glamo_mci_def_pdata.pglamo, - 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(glamo_mci_def_pdata.pglamo, + glamo_engine_disable(host->core, GLAMO_ENGINE_MMC); - regulator_disable(regulator); - host->vdd_current = -1; + + ret = regulator_disable(host->regulator); + if (ret) + 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; +} - host->real_rate = __glamo_mci_set_card_clock(host, ios->clock, &div); - host->clk_div = div; +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; - /* 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); + /* Set power */ + glamo_mci_set_power_mode(host, ios->power_mode); - 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); + 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 = ios->vdd; + } + 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 */ - host->bus_width = ios->bus_width; - if (host->bus_width == MMC_BUS_WIDTH_4) - n = GLAMO_BASIC_MMC_EN_4BIT_DATA; - writew((readw(host->base + GLAMO_REG_MMC_BASIC) & - (~(GLAMO_BASIC_MMC_EN_4BIT_DATA | - GLAMO_BASIC_MMC_EN_DR_STR0 | - GLAMO_BASIC_MMC_EN_DR_STR1))) | n | - sd_drive << 6, host->base + GLAMO_REG_MMC_BASIC); + 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 | 0xb0, + bus_width | sd_drive << 6); } @@ -908,15 +712,16 @@ 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, }; static int glamo_mci_probe(struct platform_device *pdev) { - struct mmc_host *mmc; - struct glamo_mci_host *host; + struct mmc_host *mmc; + struct glamo_mci_host *host; + struct glamo_core *core = dev_get_drvdata(pdev->dev.parent); int ret; dev_info(&pdev->dev, "glamo_mci driver (C)2007 Openmoko, Inc\n"); @@ -930,226 +735,241 @@ static int glamo_mci_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; host->pdev = pdev; - host->pdata = &glamo_mci_def_pdata; - host->power_mode_current = MMC_POWER_OFF; + if (core->pdata) + host->pdata = core->pdata->mmc_data; + host->power_mode = MMC_POWER_OFF; + host->clk_enabled = 0; + host->core = core; - host->complete_what = COMPLETION_NONE; - host->pio_active = XFER_NONE; - - spin_lock_init(&host->complete_lock); INIT_WORK(&host->irq_work, glamo_mci_irq_worker); + INIT_WORK(&host->read_work, glamo_mci_read_worker); + + host->regulator = regulator_get(pdev->dev.parent, "SD_3V3"); + if (!host->regulator) { + dev_err(&pdev->dev, "Cannot proceed without regulator.\n"); + ret = -ENODEV; + goto probe_free_host; + } - host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!host->mem) { + host->mmio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!host->mmio_mem) { dev_err(&pdev->dev, "failed to get io memory region resouce.\n"); - ret = -ENOENT; - goto probe_free_host; + goto probe_regulator_put; } - host->mem = request_mem_region(host->mem->start, - RESSIZE(host->mem), pdev->name); + host->mmio_mem = request_mem_region(host->mmio_mem->start, + resource_size(host->mmio_mem), + pdev->name); - if (!host->mem) { + if (!host->mmio_mem) { dev_err(&pdev->dev, "failed to request io memory region.\n"); ret = -ENOENT; - goto probe_free_host; + goto probe_regulator_put; } - host->base = ioremap(host->mem->start, RESSIZE(host->mem)); - if (!host->base) { + host->mmio_base = ioremap(host->mmio_mem->start, + resource_size(host->mmio_mem)); + if (!host->mmio_base) { dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); ret = -EINVAL; - goto probe_free_mem_region; + goto probe_free_mem_region_mmio; } - host->regulator = regulator_get(&pdev->dev, "SD_3V3"); - if (!host->regulator) { - dev_err(&pdev->dev, "Cannot proceed without regulator.\n"); - return -ENODEV; - } - - /* set the handler for our bit of the shared chip irq register */ - set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_MMC), glamo_mci_irq); - /* stash host as our handler's private data */ - set_irq_data(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); /* Get ahold of our data buffer we use for data in and out on MMC */ - host->mem_data = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!host->mem_data) { + host->data_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!host->data_mem) { dev_err(&pdev->dev, "failed to get io memory region resource.\n"); ret = -ENOENT; - goto probe_iounmap; + goto probe_iounmap_mmio; } - host->mem_data = request_mem_region(host->mem_data->start, - RESSIZE(host->mem_data), pdev->name); + host->data_mem = request_mem_region(host->data_mem->start, + resource_size(host->data_mem), + pdev->name); - if (!host->mem_data) { + if (!host->data_mem) { dev_err(&pdev->dev, "failed to request io memory region.\n"); ret = -ENOENT; - goto probe_iounmap; + goto probe_iounmap_mmio; } - host->base_data = ioremap(host->mem_data->start, - RESSIZE(host->mem_data)); - host->data_max_size = RESSIZE(host->mem_data); + host->data_base = ioremap(host->data_mem->start, + resource_size(host->data_mem)); - if (host->base_data == 0) { + if (host->data_base == 0) { dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); ret = -EINVAL; goto probe_free_mem_region_data; } - host->vdd_current = 0; - host->clk_rate = 50000000; /* really it's 49152000 */ - host->clk_div = 16; + ret = request_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), glamo_mci_irq, IRQF_SHARED, + pdev->name, host); + if (ret) { + dev_err(&pdev->dev, "failed to register irq.\n"); + goto probe_iounmap_data; + } + + + host->vdd = 0; + host->clk_rate = glamo_pll_rate(host->core, GLAMO_PLL1); /* explain our host controller capabilities */ - mmc->ops = &glamo_mci_ops; - mmc->ocr_avail = host->pdata->ocr_avail; - mmc->caps = MMC_CAP_4_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SD_HIGHSPEED; - mmc->f_min = host->clk_rate / 256; - mmc->f_max = sd_max_clk; - - mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */ - mmc->max_blk_size = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */ - mmc->max_req_size = RESSIZE(host->mem_data) / 2; - mmc->max_seg_size = mmc->max_req_size; - mmc->max_phys_segs = 1; /* hw doesn't talk about segs??? */ - mmc->max_hw_segs = 1; - - dev_info(&host->pdev->dev, "probe: mapped mci_base:%p irq:%u.\n", - host->base, host->irq); + mmc->ops = &glamo_mci_ops; + mmc->ocr_avail = mmc_regulator_get_ocrmask(host->regulator); + mmc->caps = MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED; + mmc->f_min = host->clk_rate / 256; + mmc->f_max = sd_max_clk; + + mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */ + mmc->max_blk_size = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */ + mmc->max_req_size = resource_size(host->data_mem); + mmc->max_seg_size = mmc->max_req_size; + mmc->max_phys_segs = 128; + mmc->max_hw_segs = 128; + + if (mmc->ocr_avail < 0) { + dev_warn(&pdev->dev, "Failed to get ocr list for regulator: %d.\n", + mmc->ocr_avail); + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + } platform_set_drvdata(pdev, mmc); - glamo_engine_enable(glamo_mci_def_pdata.pglamo, GLAMO_ENGINE_MMC); - glamo_mci_reset(host); + glamo_engine_enable(host->core, GLAMO_ENGINE_MMC); + glamo_engine_reset(host->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_free_mem_region_data; + goto probe_freeirq; } dev_info(&pdev->dev,"initialisation done.\n"); return 0; - probe_free_mem_region_data: - release_mem_region(host->mem_data->start, RESSIZE(host->mem_data)); - - probe_iounmap: - iounmap(host->base); - - probe_free_mem_region: - release_mem_region(host->mem->start, RESSIZE(host->mem)); - - probe_free_host: +probe_freeirq: + free_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); +probe_iounmap_data: + iounmap(host->data_base); +probe_free_mem_region_data: + release_mem_region(host->data_mem->start, resource_size(host->data_mem)); +probe_iounmap_mmio: + iounmap(host->mmio_base); +probe_free_mem_region_mmio: + release_mem_region(host->mmio_mem->start, resource_size(host->mmio_mem)); +probe_regulator_put: + regulator_put(host->regulator); +probe_free_host: mmc_free_host(mmc); - probe_out: +probe_out: return ret; } static int glamo_mci_remove(struct platform_device *pdev) { - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct glamo_mci_host *host = mmc_priv(mmc); - struct regulator *regulator; + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct glamo_mci_host *host = mmc_priv(mmc); + + free_irq(IRQ_GLAMO(GLAMO_IRQIDX_MMC), host); mmc_remove_host(mmc); - /* stop using our handler, revert it to default */ - set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_MMC), handle_level_irq); - iounmap(host->base); - iounmap(host->base_data); - release_mem_region(host->mem->start, RESSIZE(host->mem)); - release_mem_region(host->mem_data->start, RESSIZE(host->mem_data)); - - regulator = host->regulator; - regulator_put(regulator); - + iounmap(host->mmio_base); + iounmap(host->data_base); + release_mem_region(host->mmio_mem->start, resource_size(host->mmio_mem)); + release_mem_region(host->data_mem->start, resource_size(host->data_mem)); + + regulator_put(host->regulator); + mmc_free_host(mmc); - glamo_engine_disable(glamo_mci_def_pdata.pglamo, GLAMO_ENGINE_MMC); + glamo_engine_disable(host->core, GLAMO_ENGINE_MMC); return 0; } #ifdef CONFIG_PM -static int glamo_mci_suspend(struct platform_device *dev, pm_message_t state) +static int glamo_mci_suspend(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); - struct glamo_mci_host *host = mmc_priv(mmc); + struct mmc_host *mmc = dev_get_drvdata(dev); + 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++; - /* so that when we resume, we use any modified max rate */ - mmc->f_max = sd_max_clk; + ret = mmc_suspend_host(mmc, PMSG_SUSPEND); + glamo_mci_clock_enable(host); return ret; } -int glamo_mci_resume(struct platform_device *dev) +static int glamo_mci_resume(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); - struct glamo_mci_host *host = mmc_priv(mmc); + struct mmc_host *mmc = dev_get_drvdata(dev); + struct glamo_mci_host *host = mmc_priv(mmc); int ret; - sd_idleclk = 1; - - glamo_engine_enable(host->pdata->pglamo, GLAMO_ENGINE_MMC); - glamo_mci_reset(host); + glamo_engine_enable(host->core, GLAMO_ENGINE_MMC); + glamo_engine_reset(host->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); + +static struct dev_pm_ops glamo_mci_pm_ops = { + .suspend = glamo_mci_suspend, + .resume = glamo_mci_resume, +}; +#define GLAMO_MCI_PM_OPS (&glamo_mci_pm_ops) #else /* CONFIG_PM */ -#define glamo_mci_suspend NULL -#define glamo_mci_resume NULL +#define GLAMO_MCI_PM_OPS NULL #endif /* CONFIG_PM */ static struct platform_driver glamo_mci_driver = { - .driver.name = "glamo-mci", - .probe = glamo_mci_probe, - .remove = glamo_mci_remove, - .suspend = glamo_mci_suspend, - .resume = glamo_mci_resume, + .probe = glamo_mci_probe, + .remove = glamo_mci_remove, + .driver = { + .name = "glamo-mci", + .owner = THIS_MODULE, + .pm = GLAMO_MCI_PM_OPS, + }, }; static int __init glamo_mci_init(void) { - spin_lock_init(&clock_lock); platform_driver_register(&glamo_mci_driver); return 0; }