Commit 59af0a0b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
  omap_hsmmc: Change while(); loops with finite version
  omap_hsmmc: recover from transfer failures
  omap_hsmmc: only MMC1 allows HCTL.SDVS != 1.8V
  omap_hsmmc: card detect irq bugfix
  sdhci: fix led naming
  mmc_test: fix basic read test
  s3cmci: Fix hangup in do_pio_write()
  Revert "sdhci: force high speed capability on some controllers"
  MMC: fix bug - SDHC card capacity not correct
parents f04b30de 3ebf74b1
...@@ -584,7 +584,7 @@ static int mmc_blk_probe(struct mmc_card *card) ...@@ -584,7 +584,7 @@ static int mmc_blk_probe(struct mmc_card *card)
if (err) if (err)
goto out; goto out;
string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2, string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
cap_str, sizeof(cap_str)); cap_str, sizeof(cap_str));
printk(KERN_INFO "%s: %s %s %s %s\n", printk(KERN_INFO "%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
......
...@@ -494,7 +494,7 @@ static int mmc_test_basic_read(struct mmc_test_card *test) ...@@ -494,7 +494,7 @@ static int mmc_test_basic_read(struct mmc_test_card *test)
sg_init_one(&sg, test->buffer, 512); sg_init_one(&sg, test->buffer, 512);
ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1); ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
if (ret) if (ret)
return ret; return ret;
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#define VS30 (1 << 25) #define VS30 (1 << 25)
#define SDVS18 (0x5 << 9) #define SDVS18 (0x5 << 9)
#define SDVS30 (0x6 << 9) #define SDVS30 (0x6 << 9)
#define SDVS33 (0x7 << 9)
#define SDVSCLR 0xFFFFF1FF #define SDVSCLR 0xFFFFF1FF
#define SDVSDET 0x00000400 #define SDVSDET 0x00000400
#define AUTOIDLE 0x1 #define AUTOIDLE 0x1
...@@ -375,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status) ...@@ -375,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status)
} }
#endif /* CONFIG_MMC_DEBUG */ #endif /* CONFIG_MMC_DEBUG */
/*
* MMC controller internal state machines reset
*
* Used to reset command or data internal state machines, using respectively
* SRC or SRD bit of SYSCTL register
* Can be called from interrupt context
*/
static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host,
unsigned long bit)
{
unsigned long i = 0;
unsigned long limit = (loops_per_jiffy *
msecs_to_jiffies(MMC_TIMEOUT_MS));
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
(i++ < limit))
cpu_relax();
if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
dev_err(mmc_dev(host->mmc),
"Timeout waiting on controller reset in %s\n",
__func__);
}
/* /*
* MMC controller IRQ handler * MMC controller IRQ handler
...@@ -403,21 +430,17 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -403,21 +430,17 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
(status & CMD_CRC)) { (status & CMD_CRC)) {
if (host->cmd) { if (host->cmd) {
if (status & CMD_TIMEOUT) { if (status & CMD_TIMEOUT) {
OMAP_HSMMC_WRITE(host->base, SYSCTL, mmc_omap_reset_controller_fsm(host, SRC);
OMAP_HSMMC_READ(host->base,
SYSCTL) | SRC);
while (OMAP_HSMMC_READ(host->base,
SYSCTL) & SRC)
;
host->cmd->error = -ETIMEDOUT; host->cmd->error = -ETIMEDOUT;
} else { } else {
host->cmd->error = -EILSEQ; host->cmd->error = -EILSEQ;
} }
end_cmd = 1; end_cmd = 1;
} }
if (host->data) if (host->data) {
mmc_dma_cleanup(host); mmc_dma_cleanup(host);
mmc_omap_reset_controller_fsm(host, SRD);
}
} }
if ((status & DATA_TIMEOUT) || if ((status & DATA_TIMEOUT) ||
(status & DATA_CRC)) { (status & DATA_CRC)) {
...@@ -426,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -426,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
mmc_dma_cleanup(host); mmc_dma_cleanup(host);
else else
host->data->error = -EILSEQ; host->data->error = -EILSEQ;
OMAP_HSMMC_WRITE(host->base, SYSCTL, mmc_omap_reset_controller_fsm(host, SRD);
OMAP_HSMMC_READ(host->base,
SYSCTL) | SRD);
while (OMAP_HSMMC_READ(host->base,
SYSCTL) & SRD)
;
end_trans = 1; end_trans = 1;
} }
} }
...@@ -456,13 +474,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -456,13 +474,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
} }
/* /*
* Switch MMC operating voltage * Switch MMC interface voltage ... only relevant for MMC1.
*
* MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
* The MMC2 transceiver controls are used instead of DAT4..DAT7.
* Some chips, like eMMC ones, use internal transceivers.
*/ */
static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
{ {
u32 reg_val = 0; u32 reg_val = 0;
int ret; int ret;
if (host->id != OMAP_MMC1_DEVID)
return 0;
/* Disable the clocks */ /* Disable the clocks */
clk_disable(host->fclk); clk_disable(host->fclk);
clk_disable(host->iclk); clk_disable(host->iclk);
...@@ -485,19 +510,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) ...@@ -485,19 +510,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
reg_val = OMAP_HSMMC_READ(host->base, HCTL); reg_val = OMAP_HSMMC_READ(host->base, HCTL);
/* /*
* If a MMC dual voltage card is detected, the set_ios fn calls * If a MMC dual voltage card is detected, the set_ios fn calls
* this fn with VDD bit set for 1.8V. Upon card removal from the * this fn with VDD bit set for 1.8V. Upon card removal from the
* slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
* *
* Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is * Cope with a bit of slop in the range ... per data sheets:
* set in HCTL. * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
* but recommended values are 1.71V to 1.89V
* - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
* but recommended values are 2.7V to 3.3V
*
* Board setup code shouldn't permit anything very out-of-range.
* TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
* middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
*/ */
if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) || if ((1 << vdd) <= MMC_VDD_23_24)
((1 << vdd) == MMC_VDD_33_34)))
reg_val |= SDVS30;
if ((1 << vdd) == MMC_VDD_165_195)
reg_val |= SDVS18; reg_val |= SDVS18;
else
reg_val |= SDVS30;
OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
...@@ -517,16 +549,15 @@ static void mmc_omap_detect(struct work_struct *work) ...@@ -517,16 +549,15 @@ static void mmc_omap_detect(struct work_struct *work)
{ {
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
mmc_carddetect_work); mmc_carddetect_work);
struct omap_mmc_slot_data *slot = &mmc_slot(host);
host->carddetect = slot->card_detect(slot->card_detect_irq);
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (host->carddetect) { if (host->carddetect) {
mmc_detect_change(host->mmc, (HZ * 200) / 1000); mmc_detect_change(host->mmc, (HZ * 200) / 1000);
} else { } else {
OMAP_HSMMC_WRITE(host->base, SYSCTL, mmc_omap_reset_controller_fsm(host, SRD);
OMAP_HSMMC_READ(host->base, SYSCTL) | SRD);
while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD)
;
mmc_detect_change(host->mmc, (HZ * 50) / 1000); mmc_detect_change(host->mmc, (HZ * 50) / 1000);
} }
} }
...@@ -538,7 +569,6 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id) ...@@ -538,7 +569,6 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id)
{ {
struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id; struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
host->carddetect = mmc_slot(host).card_detect(irq);
schedule_work(&host->mmc_carddetect_work); schedule_work(&host->mmc_carddetect_work);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -757,10 +787,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -757,10 +787,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_OFF: case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
/* /*
* Reset bus voltage to 3V if it got set to 1.8V earlier. * Reset interface voltage to 3V if it's 1.8V now;
* only relevant on MMC-1, the others always use 1.8V.
*
* REVISIT: If we are able to detect cards after unplugging * REVISIT: If we are able to detect cards after unplugging
* a 1.8V card, this code should not be needed. * a 1.8V card, this code should not be needed.
*/ */
if (host->id != OMAP_MMC1_DEVID)
break;
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
int vdd = fls(host->mmc->ocr_avail) - 1; int vdd = fls(host->mmc->ocr_avail) - 1;
if (omap_mmc_switch_opcond(host, vdd) != 0) if (omap_mmc_switch_opcond(host, vdd) != 0)
...@@ -784,7 +818,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -784,7 +818,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} }
if (host->id == OMAP_MMC1_DEVID) { if (host->id == OMAP_MMC1_DEVID) {
/* Only MMC1 can operate at 3V/1.8V */ /* Only MMC1 can interface at 3V without some flavor
* of external transceiver; but they all handle 1.8V.
*/
if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
(ios->vdd == DUAL_VOLT_OCR_BIT)) { (ios->vdd == DUAL_VOLT_OCR_BIT)) {
/* /*
...@@ -1137,7 +1173,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state) ...@@ -1137,7 +1173,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
" level suspend\n"); " level suspend\n");
} }
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { if (host->id == OMAP_MMC1_DEVID
&& !(OMAP_HSMMC_READ(host->base, HCTL)
& SDVSDET)) {
OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) OMAP_HSMMC_READ(host->base, HCTL)
& SDVSCLR); & SDVSCLR);
......
...@@ -329,7 +329,7 @@ static void do_pio_write(struct s3cmci_host *host) ...@@ -329,7 +329,7 @@ static void do_pio_write(struct s3cmci_host *host)
to_ptr = host->base + host->sdidata; to_ptr = host->base + host->sdidata;
while ((fifo = fifo_free(host))) { while ((fifo = fifo_free(host)) > 3) {
if (!host->pio_bytes) { if (!host->pio_bytes) {
res = get_data_buffer(host, &host->pio_bytes, res = get_data_buffer(host, &host->pio_bytes,
&host->pio_ptr); &host->pio_ptr);
......
...@@ -144,8 +144,7 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) ...@@ -144,8 +144,7 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_DMA_SIZE |
SDHCI_QUIRK_32BIT_ADMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE |
SDHCI_QUIRK_RESET_AFTER_REQUEST | SDHCI_QUIRK_RESET_AFTER_REQUEST |
SDHCI_QUIRK_BROKEN_SMALL_PIO | SDHCI_QUIRK_BROKEN_SMALL_PIO;
SDHCI_QUIRK_FORCE_HIGHSPEED;
} }
/* /*
......
...@@ -1636,8 +1636,7 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -1636,8 +1636,7 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->f_max = host->max_clk; mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
if ((caps & SDHCI_CAN_DO_HISPD) || if (caps & SDHCI_CAN_DO_HISPD)
(host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
mmc->caps |= MMC_CAP_SD_HIGHSPEED; mmc->caps |= MMC_CAP_SD_HIGHSPEED;
mmc->ocr_avail = 0; mmc->ocr_avail = 0;
...@@ -1723,7 +1722,9 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -1723,7 +1722,9 @@ int sdhci_add_host(struct sdhci_host *host)
#endif #endif
#ifdef SDHCI_USE_LEDS_CLASS #ifdef SDHCI_USE_LEDS_CLASS
host->led.name = mmc_hostname(mmc); snprintf(host->led_name, sizeof(host->led_name),
"%s::", mmc_hostname(mmc));
host->led.name = host->led_name;
host->led.brightness = LED_OFF; host->led.brightness = LED_OFF;
host->led.default_trigger = mmc_hostname(mmc); host->led.default_trigger = mmc_hostname(mmc);
host->led.brightness_set = sdhci_led_control; host->led.brightness_set = sdhci_led_control;
......
...@@ -208,8 +208,6 @@ struct sdhci_host { ...@@ -208,8 +208,6 @@ struct sdhci_host {
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */ /* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) #define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
/* Controller supports high speed but doesn't have the caps bit set */
#define SDHCI_QUIRK_FORCE_HIGHSPEED (1<<14)
int irq; /* Device IRQ */ int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */ void __iomem * ioaddr; /* Mapped address */
...@@ -222,6 +220,7 @@ struct sdhci_host { ...@@ -222,6 +220,7 @@ struct sdhci_host {
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
struct led_classdev led; /* LED control */ struct led_classdev led; /* LED control */
char led_name[32];
#endif #endif
spinlock_t lock; /* Mutex */ spinlock_t lock; /* Mutex */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment