162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/mmc/host/pxa.c - PXA MMCI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003 Russell King, All Rights Reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This hardware is really sick: 862306a36Sopenharmony_ci * - No way to clear interrupts. 962306a36Sopenharmony_ci * - Have to turn off the clock whenever we touch the device. 1062306a36Sopenharmony_ci * - Doesn't tell you how many data blocks were transferred. 1162306a36Sopenharmony_ci * Yuck! 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * 1 and 3 byte data transfers not supported 1462306a36Sopenharmony_ci * max block length up to 1023 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/ioport.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/delay.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/dmaengine.h> 2362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2462306a36Sopenharmony_ci#include <linux/clk.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci#include <linux/mmc/host.h> 2762306a36Sopenharmony_ci#include <linux/mmc/slot-gpio.h> 2862306a36Sopenharmony_ci#include <linux/io.h> 2962306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 3062306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3162306a36Sopenharmony_ci#include <linux/gfp.h> 3262306a36Sopenharmony_ci#include <linux/of.h> 3362306a36Sopenharmony_ci#include <linux/soc/pxa/cpu.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/sizes.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/platform_data/mmc-pxamci.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "pxamci.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define DRIVER_NAME "pxa2xx-mci" 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define NR_SG 1 4462306a36Sopenharmony_ci#define CLKRT_OFF (~0) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \ 4762306a36Sopenharmony_ci || cpu_is_pxa935()) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct pxamci_host { 5062306a36Sopenharmony_ci struct mmc_host *mmc; 5162306a36Sopenharmony_ci spinlock_t lock; 5262306a36Sopenharmony_ci struct resource *res; 5362306a36Sopenharmony_ci void __iomem *base; 5462306a36Sopenharmony_ci struct clk *clk; 5562306a36Sopenharmony_ci unsigned long clkrate; 5662306a36Sopenharmony_ci unsigned int clkrt; 5762306a36Sopenharmony_ci unsigned int cmdat; 5862306a36Sopenharmony_ci unsigned int imask; 5962306a36Sopenharmony_ci unsigned int power_mode; 6062306a36Sopenharmony_ci unsigned long detect_delay_ms; 6162306a36Sopenharmony_ci bool use_ro_gpio; 6262306a36Sopenharmony_ci struct gpio_desc *power; 6362306a36Sopenharmony_ci struct pxamci_platform_data *pdata; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci struct mmc_request *mrq; 6662306a36Sopenharmony_ci struct mmc_command *cmd; 6762306a36Sopenharmony_ci struct mmc_data *data; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci struct dma_chan *dma_chan_rx; 7062306a36Sopenharmony_ci struct dma_chan *dma_chan_tx; 7162306a36Sopenharmony_ci dma_cookie_t dma_cookie; 7262306a36Sopenharmony_ci unsigned int dma_len; 7362306a36Sopenharmony_ci unsigned int dma_dir; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int pxamci_init_ocr(struct pxamci_host *host) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct mmc_host *mmc = host->mmc; 7962306a36Sopenharmony_ci int ret; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ret = mmc_regulator_get_supply(mmc); 8262306a36Sopenharmony_ci if (ret < 0) 8362306a36Sopenharmony_ci return ret; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (IS_ERR(mmc->supply.vmmc)) { 8662306a36Sopenharmony_ci /* fall-back to platform data */ 8762306a36Sopenharmony_ci mmc->ocr_avail = host->pdata ? 8862306a36Sopenharmony_ci host->pdata->ocr_mask : 8962306a36Sopenharmony_ci MMC_VDD_32_33 | MMC_VDD_33_34; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline int pxamci_set_power(struct pxamci_host *host, 9662306a36Sopenharmony_ci unsigned char power_mode, 9762306a36Sopenharmony_ci unsigned int vdd) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct mmc_host *mmc = host->mmc; 10062306a36Sopenharmony_ci struct regulator *supply = mmc->supply.vmmc; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (!IS_ERR(supply)) 10362306a36Sopenharmony_ci return mmc_regulator_set_ocr(mmc, supply, vdd); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (host->power) { 10662306a36Sopenharmony_ci bool on = !!((1 << vdd) & host->pdata->ocr_mask); 10762306a36Sopenharmony_ci gpiod_set_value(host->power, on); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (host->pdata && host->pdata->setpower) 11162306a36Sopenharmony_ci return host->pdata->setpower(mmc_dev(host->mmc), vdd); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void pxamci_stop_clock(struct pxamci_host *host) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { 11962306a36Sopenharmony_ci unsigned long timeout = 10000; 12062306a36Sopenharmony_ci unsigned int v; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci writel(STOP_CLOCK, host->base + MMC_STRPCL); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci do { 12562306a36Sopenharmony_ci v = readl(host->base + MMC_STAT); 12662306a36Sopenharmony_ci if (!(v & STAT_CLK_EN)) 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci udelay(1); 12962306a36Sopenharmony_ci } while (timeout--); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (v & STAT_CLK_EN) 13262306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "unable to stop clock\n"); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci unsigned long flags; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 14162306a36Sopenharmony_ci host->imask &= ~mask; 14262306a36Sopenharmony_ci writel(host->imask, host->base + MMC_I_MASK); 14362306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci unsigned long flags; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 15162306a36Sopenharmony_ci host->imask |= mask; 15262306a36Sopenharmony_ci writel(host->imask, host->base + MMC_I_MASK); 15362306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void pxamci_dma_irq(void *param); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx; 16162306a36Sopenharmony_ci enum dma_transfer_direction direction; 16262306a36Sopenharmony_ci struct dma_slave_config config; 16362306a36Sopenharmony_ci struct dma_chan *chan; 16462306a36Sopenharmony_ci unsigned int nob = data->blocks; 16562306a36Sopenharmony_ci unsigned long long clks; 16662306a36Sopenharmony_ci unsigned int timeout; 16762306a36Sopenharmony_ci int ret; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci host->data = data; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci writel(nob, host->base + MMC_NOB); 17262306a36Sopenharmony_ci writel(data->blksz, host->base + MMC_BLKLEN); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci clks = (unsigned long long)data->timeout_ns * host->clkrate; 17562306a36Sopenharmony_ci do_div(clks, 1000000000UL); 17662306a36Sopenharmony_ci timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 17762306a36Sopenharmony_ci writel((timeout + 255) / 256, host->base + MMC_RDTO); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memset(&config, 0, sizeof(config)); 18062306a36Sopenharmony_ci config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 18162306a36Sopenharmony_ci config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 18262306a36Sopenharmony_ci config.src_addr = host->res->start + MMC_RXFIFO; 18362306a36Sopenharmony_ci config.dst_addr = host->res->start + MMC_TXFIFO; 18462306a36Sopenharmony_ci config.src_maxburst = 32; 18562306a36Sopenharmony_ci config.dst_maxburst = 32; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 18862306a36Sopenharmony_ci host->dma_dir = DMA_FROM_DEVICE; 18962306a36Sopenharmony_ci direction = DMA_DEV_TO_MEM; 19062306a36Sopenharmony_ci chan = host->dma_chan_rx; 19162306a36Sopenharmony_ci } else { 19262306a36Sopenharmony_ci host->dma_dir = DMA_TO_DEVICE; 19362306a36Sopenharmony_ci direction = DMA_MEM_TO_DEV; 19462306a36Sopenharmony_ci chan = host->dma_chan_tx; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci config.direction = direction; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ret = dmaengine_slave_config(chan, &config); 20062306a36Sopenharmony_ci if (ret < 0) { 20162306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "dma slave config failed\n"); 20262306a36Sopenharmony_ci return; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len, 20662306a36Sopenharmony_ci host->dma_dir); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction, 20962306a36Sopenharmony_ci DMA_PREP_INTERRUPT); 21062306a36Sopenharmony_ci if (!tx) { 21162306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); 21262306a36Sopenharmony_ci return; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!(data->flags & MMC_DATA_READ)) { 21662306a36Sopenharmony_ci tx->callback = pxamci_dma_irq; 21762306a36Sopenharmony_ci tx->callback_param = host; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci host->dma_cookie = dmaengine_submit(tx); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * workaround for erratum #91: 22462306a36Sopenharmony_ci * only start DMA now if we are doing a read, 22562306a36Sopenharmony_ci * otherwise we wait until CMD/RESP has finished 22662306a36Sopenharmony_ci * before starting DMA. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) 22962306a36Sopenharmony_ci dma_async_issue_pending(chan); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci WARN_ON(host->cmd != NULL); 23562306a36Sopenharmony_ci host->cmd = cmd; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (cmd->flags & MMC_RSP_BUSY) 23862306a36Sopenharmony_ci cmdat |= CMDAT_BUSY; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) 24162306a36Sopenharmony_ci switch (RSP_TYPE(mmc_resp_type(cmd))) { 24262306a36Sopenharmony_ci case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ 24362306a36Sopenharmony_ci cmdat |= CMDAT_RESP_SHORT; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case RSP_TYPE(MMC_RSP_R3): 24662306a36Sopenharmony_ci cmdat |= CMDAT_RESP_R3; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case RSP_TYPE(MMC_RSP_R2): 24962306a36Sopenharmony_ci cmdat |= CMDAT_RESP_R2; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci default: 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci writel(cmd->opcode, host->base + MMC_CMD); 25662306a36Sopenharmony_ci writel(cmd->arg >> 16, host->base + MMC_ARGH); 25762306a36Sopenharmony_ci writel(cmd->arg & 0xffff, host->base + MMC_ARGL); 25862306a36Sopenharmony_ci writel(cmdat, host->base + MMC_CMDAT); 25962306a36Sopenharmony_ci writel(host->clkrt, host->base + MMC_CLKRT); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci writel(START_CLOCK, host->base + MMC_STRPCL); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci pxamci_enable_irq(host, END_CMD_RES); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci host->mrq = NULL; 26962306a36Sopenharmony_ci host->cmd = NULL; 27062306a36Sopenharmony_ci host->data = NULL; 27162306a36Sopenharmony_ci mmc_request_done(host->mmc, mrq); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct mmc_command *cmd = host->cmd; 27762306a36Sopenharmony_ci int i; 27862306a36Sopenharmony_ci u32 v; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!cmd) 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci host->cmd = NULL; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * Did I mention this is Sick. We always need to 28762306a36Sopenharmony_ci * discard the upper 8 bits of the first 16-bit word. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci v = readl(host->base + MMC_RES) & 0xffff; 29062306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 29162306a36Sopenharmony_ci u32 w1 = readl(host->base + MMC_RES) & 0xffff; 29262306a36Sopenharmony_ci u32 w2 = readl(host->base + MMC_RES) & 0xffff; 29362306a36Sopenharmony_ci cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; 29462306a36Sopenharmony_ci v = w2; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (stat & STAT_TIME_OUT_RESPONSE) { 29862306a36Sopenharmony_ci cmd->error = -ETIMEDOUT; 29962306a36Sopenharmony_ci } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * workaround for erratum #42: 30262306a36Sopenharmony_ci * Intel PXA27x Family Processor Specification Update Rev 001 30362306a36Sopenharmony_ci * A bogus CRC error can appear if the msb of a 136 bit 30462306a36Sopenharmony_ci * response is a one. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci if (cpu_is_pxa27x() && 30762306a36Sopenharmony_ci (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) 30862306a36Sopenharmony_ci pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); 30962306a36Sopenharmony_ci else 31062306a36Sopenharmony_ci cmd->error = -EILSEQ; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci pxamci_disable_irq(host, END_CMD_RES); 31462306a36Sopenharmony_ci if (host->data && !cmd->error) { 31562306a36Sopenharmony_ci pxamci_enable_irq(host, DATA_TRAN_DONE); 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * workaround for erratum #91, if doing write 31862306a36Sopenharmony_ci * enable DMA late 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) 32162306a36Sopenharmony_ci dma_async_issue_pending(host->dma_chan_tx); 32262306a36Sopenharmony_ci } else { 32362306a36Sopenharmony_ci pxamci_finish_request(host, host->mrq); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 1; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int pxamci_data_done(struct pxamci_host *host, unsigned int stat) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct mmc_data *data = host->data; 33262306a36Sopenharmony_ci struct dma_chan *chan; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (!data) 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 33862306a36Sopenharmony_ci chan = host->dma_chan_rx; 33962306a36Sopenharmony_ci else 34062306a36Sopenharmony_ci chan = host->dma_chan_tx; 34162306a36Sopenharmony_ci dma_unmap_sg(chan->device->dev, 34262306a36Sopenharmony_ci data->sg, data->sg_len, host->dma_dir); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (stat & STAT_READ_TIME_OUT) 34562306a36Sopenharmony_ci data->error = -ETIMEDOUT; 34662306a36Sopenharmony_ci else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) 34762306a36Sopenharmony_ci data->error = -EILSEQ; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * There appears to be a hardware design bug here. There seems to 35162306a36Sopenharmony_ci * be no way to find out how much data was transferred to the card. 35262306a36Sopenharmony_ci * This means that if there was an error on any block, we mark all 35362306a36Sopenharmony_ci * data blocks as being in error. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci if (!data->error) 35662306a36Sopenharmony_ci data->bytes_xfered = data->blocks * data->blksz; 35762306a36Sopenharmony_ci else 35862306a36Sopenharmony_ci data->bytes_xfered = 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci pxamci_disable_irq(host, DATA_TRAN_DONE); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci host->data = NULL; 36362306a36Sopenharmony_ci if (host->mrq->stop) { 36462306a36Sopenharmony_ci pxamci_stop_clock(host); 36562306a36Sopenharmony_ci pxamci_start_cmd(host, host->mrq->stop, host->cmdat); 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci pxamci_finish_request(host, host->mrq); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 1; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic irqreturn_t pxamci_irq(int irq, void *devid) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct pxamci_host *host = devid; 37662306a36Sopenharmony_ci unsigned int ireg; 37762306a36Sopenharmony_ci int handled = 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (ireg) { 38262306a36Sopenharmony_ci unsigned stat = readl(host->base + MMC_STAT); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (ireg & END_CMD_RES) 38762306a36Sopenharmony_ci handled |= pxamci_cmd_done(host, stat); 38862306a36Sopenharmony_ci if (ireg & DATA_TRAN_DONE) 38962306a36Sopenharmony_ci handled |= pxamci_data_done(host, stat); 39062306a36Sopenharmony_ci if (ireg & SDIO_INT) { 39162306a36Sopenharmony_ci mmc_signal_sdio_irq(host->mmc); 39262306a36Sopenharmony_ci handled = 1; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return IRQ_RETVAL(handled); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(mmc); 40262306a36Sopenharmony_ci unsigned int cmdat; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci WARN_ON(host->mrq != NULL); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci host->mrq = mrq; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci pxamci_stop_clock(host); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci cmdat = host->cmdat; 41162306a36Sopenharmony_ci host->cmdat &= ~CMDAT_INIT; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (mrq->data) { 41462306a36Sopenharmony_ci pxamci_setup_data(host, mrq->data); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci cmdat &= ~CMDAT_BUSY; 41762306a36Sopenharmony_ci cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; 41862306a36Sopenharmony_ci if (mrq->data->flags & MMC_DATA_WRITE) 41962306a36Sopenharmony_ci cmdat |= CMDAT_WRITE; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci pxamci_start_cmd(host, mrq->cmd, cmdat); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int pxamci_get_ro(struct mmc_host *mmc) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(mmc); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (host->use_ro_gpio) 43062306a36Sopenharmony_ci return mmc_gpio_get_ro(mmc); 43162306a36Sopenharmony_ci if (host->pdata && host->pdata->get_ro) 43262306a36Sopenharmony_ci return !!host->pdata->get_ro(mmc_dev(mmc)); 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * Board doesn't support read only detection; let the mmc core 43562306a36Sopenharmony_ci * decide what to do. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci return -ENOSYS; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(mmc); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (ios->clock) { 44562306a36Sopenharmony_ci unsigned long rate = host->clkrate; 44662306a36Sopenharmony_ci unsigned int clk = rate / ios->clock; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (host->clkrt == CLKRT_OFF) 44962306a36Sopenharmony_ci clk_prepare_enable(host->clk); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (ios->clock == 26000000) { 45262306a36Sopenharmony_ci /* to support 26MHz */ 45362306a36Sopenharmony_ci host->clkrt = 7; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci /* to handle (19.5MHz, 26MHz) */ 45662306a36Sopenharmony_ci if (!clk) 45762306a36Sopenharmony_ci clk = 1; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* 46062306a36Sopenharmony_ci * clk might result in a lower divisor than we 46162306a36Sopenharmony_ci * desire. check for that condition and adjust 46262306a36Sopenharmony_ci * as appropriate. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if (rate / clk > ios->clock) 46562306a36Sopenharmony_ci clk <<= 1; 46662306a36Sopenharmony_ci host->clkrt = fls(clk) - 1; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* 47062306a36Sopenharmony_ci * we write clkrt on the next command 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci } else { 47362306a36Sopenharmony_ci pxamci_stop_clock(host); 47462306a36Sopenharmony_ci if (host->clkrt != CLKRT_OFF) { 47562306a36Sopenharmony_ci host->clkrt = CLKRT_OFF; 47662306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (host->power_mode != ios->power_mode) { 48162306a36Sopenharmony_ci int ret; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci host->power_mode = ios->power_mode; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = pxamci_set_power(host, ios->power_mode, ios->vdd); 48662306a36Sopenharmony_ci if (ret) { 48762306a36Sopenharmony_ci dev_err(mmc_dev(mmc), "unable to set power\n"); 48862306a36Sopenharmony_ci /* 48962306a36Sopenharmony_ci * The .set_ios() function in the mmc_host_ops 49062306a36Sopenharmony_ci * struct return void, and failing to set the 49162306a36Sopenharmony_ci * power should be rare so we print an error and 49262306a36Sopenharmony_ci * return here. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci return; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (ios->power_mode == MMC_POWER_ON) 49862306a36Sopenharmony_ci host->cmdat |= CMDAT_INIT; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (ios->bus_width == MMC_BUS_WIDTH_4) 50262306a36Sopenharmony_ci host->cmdat |= CMDAT_SD_4DAT; 50362306a36Sopenharmony_ci else 50462306a36Sopenharmony_ci host->cmdat &= ~CMDAT_SD_4DAT; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n", 50762306a36Sopenharmony_ci host->clkrt, host->cmdat); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void pxamci_enable_sdio_irq(struct mmc_host *host, int enable) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct pxamci_host *pxa_host = mmc_priv(host); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (enable) 51562306a36Sopenharmony_ci pxamci_enable_irq(pxa_host, SDIO_INT); 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci pxamci_disable_irq(pxa_host, SDIO_INT); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic const struct mmc_host_ops pxamci_ops = { 52162306a36Sopenharmony_ci .request = pxamci_request, 52262306a36Sopenharmony_ci .get_cd = mmc_gpio_get_cd, 52362306a36Sopenharmony_ci .get_ro = pxamci_get_ro, 52462306a36Sopenharmony_ci .set_ios = pxamci_set_ios, 52562306a36Sopenharmony_ci .enable_sdio_irq = pxamci_enable_sdio_irq, 52662306a36Sopenharmony_ci}; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void pxamci_dma_irq(void *param) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct pxamci_host *host = param; 53162306a36Sopenharmony_ci struct dma_tx_state state; 53262306a36Sopenharmony_ci enum dma_status status; 53362306a36Sopenharmony_ci struct dma_chan *chan; 53462306a36Sopenharmony_ci unsigned long flags; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (!host->data) 53962306a36Sopenharmony_ci goto out_unlock; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (host->data->flags & MMC_DATA_READ) 54262306a36Sopenharmony_ci chan = host->dma_chan_rx; 54362306a36Sopenharmony_ci else 54462306a36Sopenharmony_ci chan = host->dma_chan_tx; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci status = dmaengine_tx_status(chan, host->dma_cookie, &state); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (likely(status == DMA_COMPLETE)) { 54962306a36Sopenharmony_ci writel(BUF_PART_FULL, host->base + MMC_PRTBUF); 55062306a36Sopenharmony_ci } else { 55162306a36Sopenharmony_ci pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc), 55262306a36Sopenharmony_ci host->data->flags & MMC_DATA_READ ? "rx" : "tx"); 55362306a36Sopenharmony_ci host->data->error = -EIO; 55462306a36Sopenharmony_ci pxamci_data_done(host, 0); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciout_unlock: 55862306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic irqreturn_t pxamci_detect_irq(int irq, void *devid) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(devid); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms)); 56662306a36Sopenharmony_ci return IRQ_HANDLED; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci#ifdef CONFIG_OF 57062306a36Sopenharmony_cistatic const struct of_device_id pxa_mmc_dt_ids[] = { 57162306a36Sopenharmony_ci { .compatible = "marvell,pxa-mmc" }, 57262306a36Sopenharmony_ci { } 57362306a36Sopenharmony_ci}; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int pxamci_of_init(struct platform_device *pdev, 57862306a36Sopenharmony_ci struct mmc_host *mmc) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 58162306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(mmc); 58262306a36Sopenharmony_ci u32 tmp; 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (!np) 58662306a36Sopenharmony_ci return 0; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* pxa-mmc specific */ 58962306a36Sopenharmony_ci if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0) 59062306a36Sopenharmony_ci host->detect_delay_ms = tmp; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci ret = mmc_of_parse(mmc); 59362306a36Sopenharmony_ci if (ret < 0) 59462306a36Sopenharmony_ci return ret; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci#else 59962306a36Sopenharmony_cistatic int pxamci_of_init(struct platform_device *pdev, 60062306a36Sopenharmony_ci struct mmc_host *mmc) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci#endif 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int pxamci_probe(struct platform_device *pdev) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct mmc_host *mmc; 60962306a36Sopenharmony_ci struct pxamci_host *host = NULL; 61062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 61162306a36Sopenharmony_ci struct resource *r; 61262306a36Sopenharmony_ci int ret, irq; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 61562306a36Sopenharmony_ci if (irq < 0) 61662306a36Sopenharmony_ci return irq; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); 61962306a36Sopenharmony_ci if (!mmc) { 62062306a36Sopenharmony_ci ret = -ENOMEM; 62162306a36Sopenharmony_ci goto out; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci mmc->ops = &pxamci_ops; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* 62762306a36Sopenharmony_ci * We can do SG-DMA, but we don't because we never know how much 62862306a36Sopenharmony_ci * data we successfully wrote to the card. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci mmc->max_segs = NR_SG; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* 63362306a36Sopenharmony_ci * Our hardware DMA can handle a maximum of one page per SG entry. 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_ci mmc->max_seg_size = PAGE_SIZE; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* 63862306a36Sopenharmony_ci * Block length register is only 10 bits before PXA27x. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* 64362306a36Sopenharmony_ci * Block count register is 16 bits. 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_ci mmc->max_blk_count = 65535; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ret = pxamci_of_init(pdev, mmc); 64862306a36Sopenharmony_ci if (ret) 64962306a36Sopenharmony_ci goto out; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci host = mmc_priv(mmc); 65262306a36Sopenharmony_ci host->mmc = mmc; 65362306a36Sopenharmony_ci host->pdata = pdev->dev.platform_data; 65462306a36Sopenharmony_ci host->clkrt = CLKRT_OFF; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci host->clk = devm_clk_get(dev, NULL); 65762306a36Sopenharmony_ci if (IS_ERR(host->clk)) { 65862306a36Sopenharmony_ci ret = PTR_ERR(host->clk); 65962306a36Sopenharmony_ci host->clk = NULL; 66062306a36Sopenharmony_ci goto out; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci host->clkrate = clk_get_rate(host->clk); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * Calculate minimum clock rate, rounding up. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci mmc->f_min = (host->clkrate + 63) / 64; 66962306a36Sopenharmony_ci mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ret = pxamci_init_ocr(host); 67262306a36Sopenharmony_ci if (ret < 0) 67362306a36Sopenharmony_ci goto out; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci mmc->caps = 0; 67662306a36Sopenharmony_ci host->cmdat = 0; 67762306a36Sopenharmony_ci if (!cpu_is_pxa25x()) { 67862306a36Sopenharmony_ci mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; 67962306a36Sopenharmony_ci host->cmdat |= CMDAT_SDIO_INT_EN; 68062306a36Sopenharmony_ci if (mmc_has_26MHz()) 68162306a36Sopenharmony_ci mmc->caps |= MMC_CAP_MMC_HIGHSPEED | 68262306a36Sopenharmony_ci MMC_CAP_SD_HIGHSPEED; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci spin_lock_init(&host->lock); 68662306a36Sopenharmony_ci host->imask = MMC_I_MASK_ALL; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); 68962306a36Sopenharmony_ci if (IS_ERR(host->base)) { 69062306a36Sopenharmony_ci ret = PTR_ERR(host->base); 69162306a36Sopenharmony_ci goto out; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci host->res = r; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * Ensure that the host controller is shut down, and setup 69762306a36Sopenharmony_ci * with our defaults. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci pxamci_stop_clock(host); 70062306a36Sopenharmony_ci writel(0, host->base + MMC_SPI); 70162306a36Sopenharmony_ci writel(64, host->base + MMC_RESTO); 70262306a36Sopenharmony_ci writel(host->imask, host->base + MMC_I_MASK); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, pxamci_irq, 0, 70562306a36Sopenharmony_ci DRIVER_NAME, host); 70662306a36Sopenharmony_ci if (ret) 70762306a36Sopenharmony_ci goto out; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci platform_set_drvdata(pdev, mmc); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci host->dma_chan_rx = dma_request_chan(dev, "rx"); 71262306a36Sopenharmony_ci if (IS_ERR(host->dma_chan_rx)) { 71362306a36Sopenharmony_ci dev_err(dev, "unable to request rx dma channel\n"); 71462306a36Sopenharmony_ci ret = PTR_ERR(host->dma_chan_rx); 71562306a36Sopenharmony_ci host->dma_chan_rx = NULL; 71662306a36Sopenharmony_ci goto out; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci host->dma_chan_tx = dma_request_chan(dev, "tx"); 72062306a36Sopenharmony_ci if (IS_ERR(host->dma_chan_tx)) { 72162306a36Sopenharmony_ci dev_err(dev, "unable to request tx dma channel\n"); 72262306a36Sopenharmony_ci ret = PTR_ERR(host->dma_chan_tx); 72362306a36Sopenharmony_ci host->dma_chan_tx = NULL; 72462306a36Sopenharmony_ci goto out; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (host->pdata) { 72862306a36Sopenharmony_ci host->detect_delay_ms = host->pdata->detect_delay_ms; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); 73162306a36Sopenharmony_ci if (IS_ERR(host->power)) { 73262306a36Sopenharmony_ci ret = PTR_ERR(host->power); 73362306a36Sopenharmony_ci dev_err(dev, "Failed requesting gpio_power\n"); 73462306a36Sopenharmony_ci goto out; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* FIXME: should we pass detection delay to debounce? */ 73862306a36Sopenharmony_ci ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); 73962306a36Sopenharmony_ci if (ret && ret != -ENOENT) { 74062306a36Sopenharmony_ci dev_err(dev, "Failed requesting gpio_cd\n"); 74162306a36Sopenharmony_ci goto out; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (!host->pdata->gpio_card_ro_invert) 74562306a36Sopenharmony_ci mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0); 74862306a36Sopenharmony_ci if (ret && ret != -ENOENT) { 74962306a36Sopenharmony_ci dev_err(dev, "Failed requesting gpio_ro\n"); 75062306a36Sopenharmony_ci goto out; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci if (!ret) 75362306a36Sopenharmony_ci host->use_ro_gpio = true; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (host->pdata->init) 75662306a36Sopenharmony_ci host->pdata->init(dev, pxamci_detect_irq, mmc); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (host->power && host->pdata->setpower) 75962306a36Sopenharmony_ci dev_warn(dev, "gpio_power and setpower() both defined\n"); 76062306a36Sopenharmony_ci if (host->use_ro_gpio && host->pdata->get_ro) 76162306a36Sopenharmony_ci dev_warn(dev, "gpio_ro and get_ro() both defined\n"); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ret = mmc_add_host(mmc); 76562306a36Sopenharmony_ci if (ret) { 76662306a36Sopenharmony_ci if (host->pdata && host->pdata->exit) 76762306a36Sopenharmony_ci host->pdata->exit(dev, mmc); 76862306a36Sopenharmony_ci goto out; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ciout: 77462306a36Sopenharmony_ci if (host) { 77562306a36Sopenharmony_ci if (host->dma_chan_rx) 77662306a36Sopenharmony_ci dma_release_channel(host->dma_chan_rx); 77762306a36Sopenharmony_ci if (host->dma_chan_tx) 77862306a36Sopenharmony_ci dma_release_channel(host->dma_chan_tx); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci if (mmc) 78162306a36Sopenharmony_ci mmc_free_host(mmc); 78262306a36Sopenharmony_ci return ret; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic void pxamci_remove(struct platform_device *pdev) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct mmc_host *mmc = platform_get_drvdata(pdev); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (mmc) { 79062306a36Sopenharmony_ci struct pxamci_host *host = mmc_priv(mmc); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci mmc_remove_host(mmc); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (host->pdata && host->pdata->exit) 79562306a36Sopenharmony_ci host->pdata->exit(&pdev->dev, mmc); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci pxamci_stop_clock(host); 79862306a36Sopenharmony_ci writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| 79962306a36Sopenharmony_ci END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, 80062306a36Sopenharmony_ci host->base + MMC_I_MASK); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci dmaengine_terminate_all(host->dma_chan_rx); 80362306a36Sopenharmony_ci dmaengine_terminate_all(host->dma_chan_tx); 80462306a36Sopenharmony_ci dma_release_channel(host->dma_chan_rx); 80562306a36Sopenharmony_ci dma_release_channel(host->dma_chan_tx); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci mmc_free_host(mmc); 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic struct platform_driver pxamci_driver = { 81262306a36Sopenharmony_ci .probe = pxamci_probe, 81362306a36Sopenharmony_ci .remove_new = pxamci_remove, 81462306a36Sopenharmony_ci .driver = { 81562306a36Sopenharmony_ci .name = DRIVER_NAME, 81662306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 81762306a36Sopenharmony_ci .of_match_table = of_match_ptr(pxa_mmc_dt_ids), 81862306a36Sopenharmony_ci }, 81962306a36Sopenharmony_ci}; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cimodule_platform_driver(pxamci_driver); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ciMODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); 82462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 82562306a36Sopenharmony_ciMODULE_ALIAS("platform:pxa2xx-mci"); 826