1eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai/* 2eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * bfin_sdh.c - Analog Devices Blackfin SDH Controller 3eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * 4eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * Copyright (C) 2007-2009 Analog Device Inc. 5eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * 6eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * Licensed under the GPL-2 or later. 7eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai */ 8eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 9eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define DRIVER_NAME "bfin-sdh" 10eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 11eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/module.h> 12eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/init.h> 13eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/ioport.h> 14eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/platform_device.h> 15eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/delay.h> 16eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/interrupt.h> 17eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/dma-mapping.h> 18eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/mmc/host.h> 19eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <linux/proc_fs.h> 205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 21eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 22eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <asm/cacheflush.h> 23eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <asm/dma.h> 24eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <asm/portmux.h> 25eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#include <asm/bfin_sdh.h> 26eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 27eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#if defined(CONFIG_BF51x) 28eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL 29eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL 30eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL 31eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL 32eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT 33eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_COMMAND bfin_write_RSI_COMMAND 34eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_DATA_TIMER bfin_write_RSI_DATA_TIMER 35eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_RESPONSE0 bfin_read_RSI_RESPONSE0 36eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_RESPONSE1 bfin_read_RSI_RESPONSE1 37eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_RESPONSE2 bfin_read_RSI_RESPONSE2 38eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_RESPONSE3 bfin_read_RSI_RESPONSE3 39eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_DATA_LGTH bfin_write_RSI_DATA_LGTH 40eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_DATA_CTL bfin_read_RSI_DATA_CTL 41eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_DATA_CTL bfin_write_RSI_DATA_CTL 42eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_DATA_CNT bfin_read_RSI_DATA_CNT 43eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUS_CLR 44eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_E_STATUS bfin_read_RSI_E_STATUS 45eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS 46eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_STATUS bfin_read_RSI_STATUS 47eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0 48eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_read_SDH_CFG bfin_read_RSI_CFG 49eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#define bfin_write_SDH_CFG bfin_write_RSI_CFG 50eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 51eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 52eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistruct dma_desc_array { 53eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned long start_addr; 54eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned short cfg; 55eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned short x_count; 56eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai short x_modify; 57eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} __packed; 58eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 59eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistruct sdh_host { 60eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_host *mmc; 61eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spinlock_t lock; 62eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct resource *res; 63eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai void __iomem *base; 64eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int irq; 65eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int stat_irq; 66eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int dma_ch; 67eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int dma_dir; 68eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct dma_desc_array *sg_cpu; 69eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_addr_t sg_dma; 70eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int dma_len; 71eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 72eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int imask; 73eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int power_mode; 74eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int clk_div; 75eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 76eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_request *mrq; 77eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_command *cmd; 78eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_data *data; 79eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai}; 80eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 81eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic struct bfin_sd_host *get_sdh_data(struct platform_device *pdev) 82eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 83eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return pdev->dev.platform_data; 84eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 85eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 86eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_stop_clock(struct sdh_host *host) 87eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 88eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() & ~CLK_E); 89eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 90eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 91eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 92eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_enable_stat_irq(struct sdh_host *host, unsigned int mask) 93eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 94eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned long flags; 95eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 96eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_lock_irqsave(&host->lock, flags); 97eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->imask |= mask; 98eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_MASK0(mask); 99eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 100eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_unlock_irqrestore(&host->lock, flags); 101eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 102eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 103eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_disable_stat_irq(struct sdh_host *host, unsigned int mask) 104eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 105eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned long flags; 106eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 107eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_lock_irqsave(&host->lock, flags); 108eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->imask &= ~mask; 109eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_MASK0(host->imask); 110eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 111eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_unlock_irqrestore(&host->lock, flags); 112eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 113eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 114eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) 115eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 116eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int length; 117eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int data_ctl; 118eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int dma_cfg; 119729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai unsigned int cycle_ns, timeout; 120eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 121eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags); 122eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->data = data; 123eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data_ctl = 0; 124eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_cfg = 0; 125eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 126eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai length = data->blksz * data->blocks; 127eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_DATA_LGTH(length); 128eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 129eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (data->flags & MMC_DATA_STREAM) 130eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data_ctl |= DTX_MODE; 131eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 132eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (data->flags & MMC_DATA_READ) 133eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data_ctl |= DTX_DIR; 134eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Only supports power-of-2 block size */ 135eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (data->blksz & (data->blksz - 1)) 136eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return -EINVAL; 137eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data_ctl |= ((ffs(data->blksz) - 1) << 4); 138eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 139eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_DATA_CTL(data_ctl); 140729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai /* the time of a host clock period in ns */ 141729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1))); 142729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai timeout = data->timeout_ns / cycle_ns; 143729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai timeout += data->timeout_clks; 144729adf1b5f4562f67fe8bf6c1df97edc1128fac7Cliff Cai bfin_write_SDH_DATA_TIMER(timeout); 145eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 146eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 147eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (data->flags & MMC_DATA_READ) { 148eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_dir = DMA_FROM_DEVICE; 149eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_cfg |= WNR; 150eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else 151eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_dir = DMA_TO_DEVICE; 152eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 153eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END)); 154eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir); 155eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#if defined(CONFIG_BF54x) 156eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN; 157eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai { 158c744d988729db9be37d1c877d143cfe63941c25cMike Frysinger struct scatterlist *sg; 159eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int i; 160eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai for_each_sg(data->sg, sg, host->dma_len, i) { 161eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].start_addr = sg_dma_address(sg); 162eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].cfg = dma_cfg; 163eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].x_count = sg_dma_len(sg) / 4; 164eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].x_modify = 4; 165eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, " 166eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n", 167eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai i, host->sg_cpu[i].start_addr, 168eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].cfg, host->sg_cpu[i].x_count, 169eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[i].x_modify); 170eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 171eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 172eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai flush_dcache_range((unsigned int)host->sg_cpu, 173eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai (unsigned int)host->sg_cpu + 174eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_len * sizeof(struct dma_desc_array)); 175eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Set the last descriptor to stop mode */ 176eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[host->dma_len - 1].cfg &= ~(DMAFLOW | NDSIZE); 177eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu[host->dma_len - 1].cfg |= DI_EN; 178eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 179eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma); 180eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_x_count(host->dma_ch, 0); 181eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_x_modify(host->dma_ch, 0); 182eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_config(host->dma_ch, dma_cfg); 183eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#elif defined(CONFIG_BF51x) 184eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* RSI DMA doesn't work in array mode */ 185eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_cfg |= WDSIZE_32 | DMAEN; 186eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0])); 187eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_x_count(host->dma_ch, length / 4); 188eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_x_modify(host->dma_ch, 4); 189eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai set_dma_config(host->dma_ch, dma_cfg); 190eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 191eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E); 192eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 193eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 194eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 195eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s exit\n", __func__); 196eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 197eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 198eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 199eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_start_cmd(struct sdh_host *host, struct mmc_command *cmd) 200eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 201eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int sdh_cmd; 202eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int stat_mask; 203eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 204eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter cmd: 0x%p\n", __func__, cmd); 205eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai WARN_ON(host->cmd != NULL); 206eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->cmd = cmd; 207eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 208eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_cmd = 0; 209eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai stat_mask = 0; 210eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 211eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_cmd |= cmd->opcode; 212eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 213eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (cmd->flags & MMC_RSP_PRESENT) { 214eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_cmd |= CMD_RSP; 215eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai stat_mask |= CMD_RESP_END; 216eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else { 217eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai stat_mask |= CMD_SENT; 218eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 219eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 220eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (cmd->flags & MMC_RSP_136) 221eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_cmd |= CMD_L_RSP; 222eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 223eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai stat_mask |= CMD_CRC_FAIL | CMD_TIME_OUT; 224eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 225eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_enable_stat_irq(host, stat_mask); 226eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 227eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_ARGUMENT(cmd->arg); 228eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_COMMAND(sdh_cmd | CMD_E); 229eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() | CLK_E); 230eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 231eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 232eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 233eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_finish_request(struct sdh_host *host, struct mmc_request *mrq) 234eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 235eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__); 236eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->mrq = NULL; 237eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->cmd = NULL; 238eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->data = NULL; 239eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_request_done(host->mmc, mrq); 240eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 241eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 242eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int sdh_cmd_done(struct sdh_host *host, unsigned int stat) 243eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 244eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_command *cmd = host->cmd; 245eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int ret = 0; 246eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 247eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter cmd: %p\n", __func__, cmd); 248eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (!cmd) 249eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 250eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 251eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->cmd = NULL; 252eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 253eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (cmd->flags & MMC_RSP_PRESENT) { 254eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->resp[0] = bfin_read_SDH_RESPONSE0(); 255eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (cmd->flags & MMC_RSP_136) { 256eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->resp[1] = bfin_read_SDH_RESPONSE1(); 257eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->resp[2] = bfin_read_SDH_RESPONSE2(); 258eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->resp[3] = bfin_read_SDH_RESPONSE3(); 259eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 260eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 261eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (stat & CMD_TIME_OUT) 262eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->error = -ETIMEDOUT; 263eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai else if (stat & CMD_CRC_FAIL && cmd->flags & MMC_RSP_CRC) 264eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cmd->error = -EILSEQ; 265eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 266eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_disable_stat_irq(host, (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL)); 267eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 268eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (host->data && !cmd->error) { 269eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (host->data->flags & MMC_DATA_WRITE) { 270eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = sdh_setup_data(host, host->data); 271eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) 272eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 273eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 274eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 275eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_enable_stat_irq(host, DAT_END | RX_OVERRUN | TX_UNDERRUN | DAT_TIME_OUT); 276eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else 277eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_finish_request(host, host->mrq); 278eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 279eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 1; 280eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 281eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 282eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int sdh_data_done(struct sdh_host *host, unsigned int stat) 283eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 284eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_data *data = host->data; 285eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 286eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter stat: 0x%x\n", __func__, stat); 287eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (!data) 288eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 289eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 290eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai disable_dma(host->dma_ch); 291eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 292eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_dir); 293eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 294eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (stat & DAT_TIME_OUT) 295eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data->error = -ETIMEDOUT; 296eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai else if (stat & DAT_CRC_FAIL) 297eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data->error = -EILSEQ; 298eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai else if (stat & (RX_OVERRUN | TX_UNDERRUN)) 299eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data->error = -EIO; 300eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 301eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (!data->error) 302eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data->bytes_xfered = data->blocks * data->blksz; 303eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai else 304eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai data->bytes_xfered = 0; 305eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 306eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN); 307eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \ 308eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN); 309eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_DATA_CTL(0); 310eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 311eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 312eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->data = NULL; 313eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (host->mrq->stop) { 314eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_stop_clock(host); 315eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_start_cmd(host, host->mrq->stop); 316eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else { 317eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_finish_request(host, host->mrq); 318eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 319eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 320eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 1; 321eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 322eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 323eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq) 324eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 325eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host = mmc_priv(mmc); 326eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int ret = 0; 327eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 328eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd); 329eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai WARN_ON(host->mrq != NULL); 330eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 331eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->mrq = mrq; 332eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->data = mrq->data; 333eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 334eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (mrq->data && mrq->data->flags & MMC_DATA_READ) { 335eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = sdh_setup_data(host, mrq->data); 336eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) 337eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return; 338eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 339eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 340eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_start_cmd(host, mrq->cmd); 341eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 342eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 343eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 344eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 345eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host; 346eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned long flags; 347eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai u16 clk_ctl = 0; 348eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai u16 pwr_ctl = 0; 349eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai u16 cfg; 350eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host = mmc_priv(mmc); 351eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 352eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_lock_irqsave(&host->lock, flags); 353eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ios->clock) { 354eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned long sys_clk, ios_clk; 355eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned char clk_div; 356eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ios_clk = 2 * ios->clock; 357eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sys_clk = get_sclk(); 358eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_div = sys_clk / ios_clk; 359eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (sys_clk % ios_clk == 0) 360eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_div -= 1; 361eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_div = min_t(unsigned char, clk_div, 0xFF); 362eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_ctl |= clk_div; 363eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_ctl |= CLK_E; 364eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->clk_div = clk_div; 365eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else 366eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_stop_clock(host); 367eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 368eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) 369eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND 370eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai pwr_ctl |= ROD_CTL; 371eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#else 372eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai pwr_ctl |= SD_CMD_OD | ROD_CTL; 373eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 374eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 375eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ios->bus_width == MMC_BUS_WIDTH_4) { 376eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg = bfin_read_SDH_CFG(); 377eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg &= ~PD_SDDAT3; 378eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg |= PUP_SDDAT3; 379eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Enable 4 bit SDIO */ 380eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg |= (SD4E | MWE); 381eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG(cfg); 382eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clk_ctl |= WIDE_BUS; 383eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } else { 384eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg = bfin_read_SDH_CFG(); 385eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai cfg |= MWE; 386eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG(cfg); 387eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 388eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 389eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CLK_CTL(clk_ctl); 390eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 391eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->power_mode = ios->power_mode; 392eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ios->power_mode == MMC_POWER_ON) 393eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai pwr_ctl |= PWR_ON; 394eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 395eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_PWR_CTL(pwr_ctl); 396eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 397eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 398eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_unlock_irqrestore(&host->lock, flags); 399eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 400eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n", 401eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->clk_div, 402eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->clk_div ? get_sclk() / (2 * (host->clk_div + 1)) : 0, 403eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ios->clock); 404eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 405eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 406eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic const struct mmc_host_ops sdh_ops = { 407eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .request = sdh_request, 408eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .set_ios = sdh_set_ios, 409eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai}; 410eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 411eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic irqreturn_t sdh_dma_irq(int irq, void *devid) 412eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 413eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host = devid; 414eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 415eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__, 416eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai get_dma_curr_irqstat(host->dma_ch)); 417eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai clear_dma_irqstat(host->dma_ch); 418eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 419eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 420eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return IRQ_HANDLED; 421eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 422eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 423eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic irqreturn_t sdh_stat_irq(int irq, void *devid) 424eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 425eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host = devid; 426eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai unsigned int status; 427eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int handled = 0; 428eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 429eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__); 430eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai status = bfin_read_SDH_E_STATUS(); 431eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (status & SD_CARD_DET) { 432eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_detect_change(host->mmc, 0); 433eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_E_STATUS(SD_CARD_DET); 434eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 435eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai status = bfin_read_SDH_STATUS(); 436eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL)) { 437eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai handled |= sdh_cmd_done(host, status); 438eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | \ 439eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT); 440eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 441eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 442eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 443eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai status = bfin_read_SDH_STATUS(); 444eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN)) 445eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai handled |= sdh_data_done(host, status); 446eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 447eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__); 448eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 449eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return IRQ_RETVAL(handled); 450eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 451eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 452eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int __devinit sdh_probe(struct platform_device *pdev) 453eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 454eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_host *mmc; 455eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host; 456eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct bfin_sd_host *drv_data = get_sdh_data(pdev); 457eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int ret; 458eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 459eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (!drv_data) { 460eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&pdev->dev, "missing platform driver data\n"); 461eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = -EINVAL; 462eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out; 463eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 464eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 465a34650f0f1ca589cda09c48cb62baf15e680a247Sonic Zhang mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev); 466eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (!mmc) { 467eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = -ENOMEM; 468eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out; 469eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 470eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 471eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->ops = &sdh_ops; 472a36274e0184193e393fb82957925c3981a6b0477Martin K. Petersen mmc->max_segs = 32; 473eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->max_seg_size = 1 << 16; 474eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->max_blk_size = 1 << 11; 475eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->max_blk_count = 1 << 11; 476eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->max_req_size = PAGE_SIZE; 477eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 478eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->f_max = get_sclk(); 479eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->f_min = mmc->f_max >> 9; 480eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL; 481eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host = mmc_priv(mmc); 482eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->mmc = mmc; 483eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 484eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai spin_lock_init(&host->lock); 485eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->irq = drv_data->irq_int0; 486eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->dma_ch = drv_data->dma_chan; 487eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 488eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = request_dma(host->dma_ch, DRIVER_NAME "DMA"); 489eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) { 490eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&pdev->dev, "unable to request DMA channel\n"); 491eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out1; 492eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 493eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 494eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = set_dma_callback(host->dma_ch, sdh_dma_irq, host); 495eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) { 496eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&pdev->dev, "unable to request DMA irq\n"); 497eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out2; 498eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 499eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 500eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); 501eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (host->sg_cpu == NULL) { 502eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = -ENOMEM; 503eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out2; 504eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 505eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 506eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai platform_set_drvdata(pdev, mmc); 507eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_add_host(mmc); 508eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 509eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host); 510eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) { 511eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&pdev->dev, "unable to request status irq\n"); 512eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out3; 513eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 514eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 515eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME); 516eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) { 517eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&pdev->dev, "unable to request peripheral pins\n"); 518eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai goto out4; 519eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 520eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#if defined(CONFIG_BF54x) 521eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Secure Digital Host shares DMA with Nand controller */ 522eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); 523eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 524eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 525eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); 526eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 527eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 528eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and 529eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai * mmc stack will do the detection. 530eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai */ 531eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); 532eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 533eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 534eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 535eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 536eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caiout4: 537eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai free_irq(host->irq, host); 538eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caiout3: 539eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_remove_host(mmc); 540eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 541eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caiout2: 542eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai free_dma(host->dma_ch); 543eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caiout1: 544eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_free_host(mmc); 545eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai out: 546eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return ret; 547eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 548eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 549eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int __devexit sdh_remove(struct platform_device *pdev) 550eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 551eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_host *mmc = platform_get_drvdata(pdev); 552eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 553eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai platform_set_drvdata(pdev, NULL); 554eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 555eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (mmc) { 556eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct sdh_host *host = mmc_priv(mmc); 557eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 558eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_remove_host(mmc); 559eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 560eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai sdh_stop_clock(host); 561eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai free_irq(host->irq, host); 562eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai free_dma(host->dma_ch); 563eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 564eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 565eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai mmc_free_host(mmc); 566eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 567eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 568eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return 0; 569eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 570eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 571eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#ifdef CONFIG_PM 572eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int sdh_suspend(struct platform_device *dev, pm_message_t state) 573eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 574eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_host *mmc = platform_get_drvdata(dev); 575eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct bfin_sd_host *drv_data = get_sdh_data(dev); 576eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int ret = 0; 577eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 578eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (mmc) 5791a13f8fa76c880be41d6b1e6a2b44404bcbfdf9eMatt Fleming ret = mmc_suspend_host(mmc); 580eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 581eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON); 582eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai peripheral_free_list(drv_data->pin_req); 583eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 584eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return ret; 585eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 586eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 587eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic int sdh_resume(struct platform_device *dev) 588eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai{ 589eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct mmc_host *mmc = platform_get_drvdata(dev); 590eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai struct bfin_sd_host *drv_data = get_sdh_data(dev); 591eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai int ret = 0; 592eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 593eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME); 594eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (ret) { 595eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai dev_err(&dev->dev, "unable to request peripheral pins\n"); 596eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return ret; 597eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai } 598eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 599eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON); 600eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#if defined(CONFIG_BF54x) 601eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai /* Secure Digital Host shares DMA with Nand controller */ 602eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1); 603eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 604eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN); 605eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 606eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 607eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3)); 608eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai SSYNC(); 609eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 610eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai if (mmc) 611eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai ret = mmc_resume_host(mmc); 612eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 613eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai return ret; 614eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai} 615eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#else 616eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai# define sdh_suspend NULL 617eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai# define sdh_resume NULL 618eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai#endif 619eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 620eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Caistatic struct platform_driver sdh_driver = { 621eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .probe = sdh_probe, 622eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .remove = __devexit_p(sdh_remove), 623eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .suspend = sdh_suspend, 624eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .resume = sdh_resume, 625eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .driver = { 626eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai .name = DRIVER_NAME, 627eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai }, 628eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai}; 629eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 630d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(sdh_driver); 631eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff Cai 632eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff CaiMODULE_DESCRIPTION("Blackfin Secure Digital Host Driver"); 633eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff CaiMODULE_AUTHOR("Cliff Cai, Roy Huang"); 634eb962d5bb7da4f25e20e5d448ee3aac394144ff6Cliff CaiMODULE_LICENSE("GPL"); 635