⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mhn_controller.c

📁 spi driver code one marve
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * mhn_controller.c - MMC/SD/SDIO Controller driver * * Copyright (C) 2006 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *(C) Copyright 2006 Marvell International Ltd.   * All Rights Reserved  */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/blkdev.h>#include <linux/dma-mapping.h>#include <linux/wait.h>#include <linux/suspend.h>#include <asm/uaccess.h>#include <asm/hardware.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/sizes.h>#include <asm/types.h>#include <asm/dma-mapping.h>#include <asm/arch/pxa-regs.h>#include <asm/arch/gpio.h>#include <asm/arch/cpu-freq-voltage-mhn.h>#include <asm/arch/mhn_pmic.h>#include <asm/arch/arava.h>#ifdef	CONFIG_MACH_ZYLONITE#include <asm/arch/zylonite.h>#elif	defined (CONFIG_MACH_LITTLETON)#include <asm/arch/littleton.h>#else#error	"Please select correct Platform for build"#endif#include "mhn_controller.h"#define PXA_SLOT_SCAN	1#define PXA_SLOT_EXIT	2struct pxa_slot {	u32 cd_irq;	u32 cd_gpio;	u32 wp_gpio;#if 0	struct completion	thread_complete;	struct semaphore	thread_sem;	wait_queue_head_t	thread_wq;	int flags;#endif	struct work_struct	sdio_int;	struct work_struct	card_change;};#if   defined(CONFIG_CPU_MONAHANS_P) ||		\	defined(CONFIG_CPU_MONAHANS_PL) || 	\	defined(CONFIG_CPU_MONAHANS_L)static u32 PXA_HOST_IRQ[PXA_MMC_MAX] = {IRQ_MMC, IRQ_MMC2};static u32 PXA_HOST_DRCMRTX[PXA_MMC_MAX] 			= {(u32)&(DRCMRTXMMC), (u32)&(DRCMRTXMMC2)};static u32 PXA_HOST_DRCMRRX[PXA_MMC_MAX]			= {(u32)&(DRCMRRXMMC), (u32)&(DRCMRRXMMC2)};#ifdef CONFIG_MMC1_SLOT1static u32 PXA_HOST_SLOTS[PXA_MMC_MAX] = {2, 1};#elsestatic u32 PXA_HOST_SLOTS[PXA_MMC_MAX] = {1, 1};#endifstatic u32 PXA_HOST_BASE[PXA_MMC_MAX] = {(u32)&(__REG(0x41100000)), 	(u32)&(__REG_2(0x42000000))};static u32 PXA_HOST_PHYBASE[PXA_MMC_MAX] = {0x41100000, 0x42000000};static u32 PXA_HOST_CKEN[PXA_MMC_MAX] = {CKEN_MMC1, CKEN_MMC2};#elif defined(CONFIG_CPU_MONAHANS_LV)static u32 PXA_HOST_IRQ[PXA_MMC_MAX] = {IRQ_MMC, IRQ_MMC2, IRQ_MMC3};static u32 PXA_HOST_DRCMRTX[PXA_MMC_MAX] 			= {(u32)&(DRCMRTXMMC), (u32)&(DRCMRTXMMC2), 				(u32)&(DRCMRTXMMC3)};static u32 PXA_HOST_DRCMRRX[PXA_MMC_MAX]			= {(u32)&(DRCMRRXMMC), (u32)&(DRCMRRXMMC2), 				(u32)&(DRCMRRXMMC3)};#ifdef CONFIG_MMC1_SLOT1static u32 PXA_HOST_SLOTS[PXA_MMC_MAX] = {2, 1, 1};#elsestatic u32 PXA_HOST_SLOTS[PXA_MMC_MAX] = {1, 1, 1};#endifstatic u32 PXA_HOST_BASE[PXA_MMC_MAX] = {(u32)&(__REG(0x41100000)), 	(u32)&(__REG_2(0x42000000)), (u32)&(__REG_4(0x42500000))};static u32 PXA_HOST_PHYBASE[PXA_MMC_MAX] = {0x41100000, 0x42000000, 0x42500000};static u32 PXA_HOST_CKEN[PXA_MMC_MAX] = {CKEN_MMC1, CKEN_MMC2, CKEN_MMC3};#endif/*  enable controller INT according to mask */static void pxa_host_enable_int(struct pxa_mss_host *pxa_host, unsigned int mask){	u32 i_reg = 0;	unsigned long flags;	local_irq_save(flags);	i_reg = readl(pxa_host->base + MMC_I_MASK);	i_reg &= ~mask;	writel(i_reg, pxa_host->base + MMC_I_MASK);	i_reg = readl(pxa_host->base + MMC_I_MASK);	local_irq_restore(flags);}/* *  disable controller INT according to mask */static void pxa_host_disable_int(struct pxa_mss_host *pxa_host, unsigned int mask){	u32 i_reg;	unsigned long flags;	local_irq_save(flags);	i_reg = readl(pxa_host->base + MMC_I_MASK);	i_reg |= mask;	writel(i_reg, pxa_host->base + MMC_I_MASK);	i_reg = readl(pxa_host->base + MMC_I_MASK);	local_irq_restore(flags);}static void pxa_host_start_busclock(struct pxa_mss_host *pxa_host){	u32 retries = 0xff;		writel(MMC_STRPCL_START_CLOCK, pxa_host->base + MMC_STRPCL);	while (retries--) {		if (readl(pxa_host->base + MMC_STAT) & MMC_STAT_CLOCK_ON);			break;		udelay(1);	}}static void pxa_host_stop_busclock(struct pxa_mss_host *pxa_host){	u32 retries = 0xff;		writel(MMC_STRPCL_STOP_CLOCK, pxa_host->base + MMC_STRPCL);	while (retries--) {		if (readl(pxa_host->base + MMC_I_REG) & MMC_I_REG_CLK_OFF)			break;		udelay(1);	}}/* *  setup DMA controller for data transfer  */static void pxa_host_setup_data(struct pxa_mss_host *pxa_host,		struct mss_data *data){	u32 dcmd = 0;	int i;	struct mss_host *host = pxa_host->host;	writel(data->blocks, pxa_host->base + MMC_NUMBLK);	writel(data->blksz, pxa_host->base + MMC_BLKLEN);	if (data->flags & MSS_DATA_READ) { /*read*/		dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;		writel(0x0, pxa_host->drcmrtx);		writel(pxa_host->dma | DRCMR_MAPVLD, pxa_host->drcmrrx);	} else if (data->flags & MSS_DATA_WRITE ) { /*write*/		dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;		writel(0x0, pxa_host->drcmrrx);		writel(pxa_host->dma | DRCMR_MAPVLD, pxa_host->drcmrtx);	} else {		BUG();	}	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;	dbg("read to set up dma., sg_len:%d", data->sg_len);	pxa_host->sg_idx = 0;	pxa_host->dma_len = dma_map_sg(host->dev, data->sg, data->sg_len, 			(data->flags & MSS_DATA_READ) ? 			DMA_FROM_DEVICE : DMA_TO_DEVICE);	for (i = 0; i < pxa_host->dma_len; i++) {		data->bytes_xfered += sg_dma_len(&data->sg[i]);		if (data->flags & MSS_DATA_READ) {			pxa_host->sg_cpu[i].dsadr = 				pxa_host->phybase + MMC_RXFIFO;			pxa_host->sg_cpu[i].dtadr = 				sg_dma_address(&data->sg[i]);		}		else {			pxa_host->sg_cpu[i].dsadr = 				sg_dma_address(&data->sg[i]);			pxa_host->sg_cpu[i].dtadr = 				pxa_host->phybase + MMC_TXFIFO;		}		pxa_host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);		pxa_host->sg_cpu[i].ddadr = pxa_host->sg_dma + (i + 1) *					sizeof(struct pxa_dma_desc);		dbg("sg:%d, dsadr:0x%x, dtadr:0x%x, dcmd:0x%x, ddadr:0x%x\n", i,			pxa_host->sg_cpu[i].dsadr, pxa_host->sg_cpu[i].dtadr, 			pxa_host->sg_cpu[i].dcmd, pxa_host->sg_cpu[i].ddadr);	}	pxa_host->sg_cpu[pxa_host->dma_len - 1].ddadr = DDADR_STOP;	pxa_host->sg_cpu[pxa_host->dma_len - 1].dcmd |= DCMD_ENDIRQEN;	wmb();}/* *  read response of MMC/SD/SDIO controller. */static void pxa_host_get_response(struct pxa_mss_host *pxa_host,		struct mss_cmd *cmd){	int i;	u32 mmc_res;	for (i = 0; i < PXA_MSS_MAX_RESPONSE_SIZE; i = i + 2) {		mmc_res = readl(pxa_host->base + MMC_RES);		if (i < MSS_MAX_RESPONSE_SIZE) {			cmd->response[i] = mmc_res >> 8;			cmd->response[i + 1] = mmc_res & 0xff;		}	}#ifdef CONFIG_MMC_DEBUG	printk(KERN_INFO "Response for CMD 0x%x, RES:", cmd->opcode);	for (i = 0; i < PXA_MSS_MAX_RESPONSE_SIZE; i++) 		printk("0x%x,", cmd->response[i]);	printk("\n");#endif}/* *  set io_request result according to error status in MMC/SD/SDIO controller  *  status reg. */static void pxa_host_set_error(struct mss_cmd *cmd, u32 stat){	if (stat & MMC_STAT_RESP_TIMEOUT ) 		cmd->error = MSS_ERROR_TIMEOUT;	/*else if (stat & MMC_STAT_RESP_CRC) 		cmd->error = MSS_ERROR_CRC;*/	else if (stat & MMC_STAT_FLASH_ERR)		cmd->error = MSS_ERROR_FLASH;	else if (stat & MMC_STAT_READ_TIMEOUT)		cmd->error = MSS_ERROR_TIMEOUT;	else if (stat & (MMC_STAT_READ_CRC | MMC_STAT_WRITE_CRC))		cmd->error = MSS_ERROR_CRC;	dbg("Error %d for command: 0x%x\n", cmd->error, cmd->opcode);}static inline int get_slot_cd_irq(struct mss_slot *slot) {	return ((struct pxa_slot *)slot->private)->cd_irq;}static inline void set_slot_cd_irq(struct mss_slot *slot, int cd_irq){	((struct pxa_slot *)slot->private)->cd_irq = cd_irq;}static inline int get_slot_cd_gpio(struct mss_slot *slot) {	return ((struct pxa_slot *)slot->private)->cd_gpio;}static inline void set_slot_cd_gpio(struct mss_slot *slot, int cd_gpio){	((struct pxa_slot *)slot->private)->cd_gpio = cd_gpio;}static inline int get_slot_wp_gpio(struct mss_slot *slot) {	return ((struct pxa_slot *)slot->private)->wp_gpio;}static inline void set_slot_wp_gpio(struct mss_slot *slot, int wp_gpio){	((struct pxa_slot *)slot->private)->wp_gpio = wp_gpio;}#ifdef	CONFIG_MACH_ZYLONITEstatic void pxa_mss_slot_select(struct mss_slot *slot){	if (slot->host->id == PXA_MMC_1) {		if (slot->id == 0) {			mhn_mfp_set_afds(MFP_MMC_CMD_0, MFP_AF4, MFP_DS03X);			/* set to GPIO output high for CMD_1 pin */			mhn_mfp_set_afds(MFP_MMC_CMD_1, MFP_AF0, MFP_DS03X);			mhn_gpio_set_direction(MFP_MMC_CMD_1, GPIO_DIR_OUT);			mhn_gpio_set_level(MFP_MMC_CMD_1, GPIO_LEVEL_HIGH);  		} else if (slot->id == 1) {			mhn_mfp_set_afds(MFP_MMC_CMD_1, MFP_MMC_CMD_1_AF,					MFP_DS03X);			/* set to GPIO output high for CMD_0 pin */ 			mhn_mfp_set_afds(MFP_MMC_CMD_0, MFP_AF0, MFP_DS03X);			mhn_gpio_set_direction(MFP_MMC_CMD_0, GPIO_DIR_OUT);			mhn_gpio_set_level(MFP_MMC_CMD_0, GPIO_LEVEL_HIGH);		} else			BUG();	} else if(slot->host->id == PXA_MMC_2) {		mhn_mfp_set_afds(MFP_MMC2_CMD, MFP_AF4, MFP_DS03X);	}#if defined(CONFIG_CPU_MONAHANS_LV)	else if(slot->host->id == PXA_MMC_3) {		mhn_mfp_set_afds(MFP_MMC3_CMD, MFP_MMC3_CMD_AF, MFP_DS03X);	}#endif	else		BUG();}#elif	defined (CONFIG_MACH_LITTLETON)static void pxa_mss_slot_select(struct mss_slot *slot){	if (slot->host->id == PXA_MMC_1) {		if (slot->id == 0) {			mhn_mfp_set_afds(MFP_MMC_CMD_0, MFP_AF4, MFP_DS03X);		} else if (slot->id == 1) {			/* set to GPIO output high for CMD_0 pin */ 			mhn_mfp_set_afds(MFP_MMC_CMD_0, MFP_AF0, MFP_DS03X);			mhn_gpio_set_direction(MFP_MMC_CMD_0, GPIO_DIR_OUT);			mhn_gpio_set_level(MFP_MMC_CMD_0, GPIO_LEVEL_HIGH);		} else			BUG();	} else if(slot->host->id == PXA_MMC_2) {		mhn_mfp_set_afds(MFP_MMC2_CMD, MFP_AF4, MFP_DS03X);	}#if defined(CONFIG_CPU_MONAHANS_LV)	else if(slot->host->id == PXA_MMC_3) {		mhn_mfp_set_afds(MFP_MMC3_CMD, MFP_MMC3_CMD_AF, MFP_DS03X);	}#endif	else		BUG();}#else#error	"Please select correct platform for build"#endif/* *  return value: 0 -- not write-protected, 1 -- write-protected */static int pxa_mss_slot_is_wp(struct mss_slot *slot){	u32 wp_gpio = get_slot_wp_gpio(slot);	u32 level = GPIO_LEVEL_LOW;	if (wp_gpio)		level = mhn_gpio_get_level(wp_gpio);		dbg("host%d, slot%d wp is %s", slot->host->id, slot->id, 			(level == GPIO_LEVEL_HIGH) ? "TRUE":"FALSE");	return (level == GPIO_LEVEL_HIGH);}/* *  return value: 0 -- inserted, 1 -- empty. */static int pxa_mss_slot_is_empty(struct mss_slot *slot){	u32 cd_gpio = get_slot_cd_gpio(slot);	if (cd_gpio) {		int empty = (mhn_gpio_get_level(cd_gpio) == GPIO_LEVEL_HIGH);		return empty;		}		return 0;}static void pxa_mss_set_ios(struct mss_host *host, struct mss_ios *ios){	unsigned int clockrate;	struct pxa_mss_host *pxa_host;       	pxa_host = host->private;		dbg("clock now %d, to set %d, CLKRT:%x", host->ios.clock, ios->clock, 			readl(pxa_host->base + MMC_CLKRT));	if (ios->clock != host->ios.clock) {#if	defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV) 		if (ios->clock >= 26000000) {			host->ios.clock = 26000000;			clockrate = CLKRT_26MHZ;		}		else if (ios->clock >= 19500000)#else		if (ios->clock >= 19500000)#endif		{			host->ios.clock = 19500000;			clockrate = CLKRT_19_5MHZ;		}		else if (ios->clock >= 9750000) {			host->ios.clock = 9750000;			clockrate = CLKRT_9_75MHZ;		}		else if (ios->clock >= 4875000) {			host->ios.clock = 4875000;			clockrate = CLKRT_4_88MHZ;		}		else if (ios->clock >= 2437500) {			host->ios.clock = 2437500;			clockrate = CLKRT_2_44MHZ;		}			else if (ios->clock >= 1218750) {			host->ios.clock = 1218750;			clockrate = CLKRT_1_22MHZ;     		}		else if (ios->clock >= 609375){			host->ios.clock = 609375;			clockrate = CLKRT_0_609MHZ; 		}			else {			host->ios.clock = 304000;			clockrate = CLKRT_0_304MHZ; 		}		pxa_host_stop_busclock(pxa_host);		writel(clockrate, pxa_host->base + MMC_CLKRT);		pxa_host_start_busclock(pxa_host);	}	host->ios.bus_width = ios->bus_width;	if (host->ios.bus_width > host->bus_width)		host->ios.bus_width = host->bus_width;}#ifdef CONFIG_DVFMstatic int mhn_mmc_dvfm_notifier(unsigned cmd, void *client_data, void *info){	struct pxa_mss_host *pxa_host = (struct pxa_mss_host *)client_data;	switch (cmd) {	case FV_NOTIFIER_QUERY_SET :		if (pxa_host->dma_run)			return -1;		break;	case FV_NOTIFIER_PRE_SET :		break;	case FV_NOTIFIER_POST_SET :		break;	}	return 0;}#endif/* *  send command by setting CMDAT reg of MMC/SD/SDIO controller. *  Note: to hide info about SD/SDIO. */static void pxa_mss_handle_request(struct mss_host *host,		struct mss_ll_request *llreq){	struct pxa_mss_host *pxa_host = host->private;	struct mss_cmd *cmd;	struct mss_card *card = host->active_card;	u32 cmd_dat = 0;	dbg("pxammc %d acitive slot %x\n", host->id + 1,		(pxa_host->active_slot) ? pxa_host->active_slot->id : -1);	if (pxa_host->active_slot != card->slot) {		dbg("pxammc %d change acitive slot to %d\n", host->id + 1, 				card->slot->id);		pxa_mss_slot_select(card->slot);		pxa_host->active_slot = card->slot;	}	pxa_host->cmd = llreq->cmd;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -