1/* linux/arch/arm/mach-msm/board-trout-mmc.c 2** Author: Brian Swetland <swetland@google.com> 3*/ 4 5#include <linux/kernel.h> 6#include <linux/init.h> 7#include <linux/platform_device.h> 8#include <linux/delay.h> 9#include <linux/mmc/host.h> 10#include <linux/mmc/sdio_ids.h> 11#include <linux/err.h> 12#include <linux/debugfs.h> 13 14#include <asm/gpio.h> 15#include <asm/io.h> 16 17#include <mach/vreg.h> 18 19#include <mach/mmc.h> 20 21#include "devices.h" 22 23#include "board-trout.h" 24 25#include "proc_comm.h" 26 27#define DEBUG_SDSLOT_VDD 1 28 29/* ---- COMMON ---- */ 30static void config_gpio_table(uint32_t *table, int len) 31{ 32 int n; 33 unsigned id; 34 for(n = 0; n < len; n++) { 35 id = table[n]; 36 msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); 37 } 38} 39 40/* ---- SDCARD ---- */ 41 42static uint32_t sdcard_on_gpio_table[] = { 43 PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ 44 PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ 45 PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */ 46 PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */ 47 PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ 48 PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ 49}; 50 51static uint32_t sdcard_off_gpio_table[] = { 52 PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ 53 PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ 54 PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ 55 PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ 56 PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ 57 PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ 58}; 59 60static uint opt_disable_sdcard; 61 62static int __init trout_disablesdcard_setup(char *str) 63{ 64 int cal = simple_strtol(str, NULL, 0); 65 66 opt_disable_sdcard = cal; 67 return 1; 68} 69 70__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup); 71 72static struct vreg *vreg_sdslot; /* SD slot power */ 73 74struct mmc_vdd_xlat { 75 int mask; 76 int level; 77}; 78 79static struct mmc_vdd_xlat mmc_vdd_table[] = { 80 { MMC_VDD_165_195, 1800 }, 81 { MMC_VDD_20_21, 2050 }, 82 { MMC_VDD_21_22, 2150 }, 83 { MMC_VDD_22_23, 2250 }, 84 { MMC_VDD_23_24, 2350 }, 85 { MMC_VDD_24_25, 2450 }, 86 { MMC_VDD_25_26, 2550 }, 87 { MMC_VDD_26_27, 2650 }, 88 { MMC_VDD_27_28, 2750 }, 89 { MMC_VDD_28_29, 2850 }, 90 { MMC_VDD_29_30, 2950 }, 91}; 92 93static unsigned int sdslot_vdd = 0xffffffff; 94static unsigned int sdslot_vreg_enabled; 95 96static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd) 97{ 98 int i, rc; 99 100 BUG_ON(!vreg_sdslot); 101 102 if (vdd == sdslot_vdd) 103 return 0; 104 105 sdslot_vdd = vdd; 106 107 if (vdd == 0) { 108#if DEBUG_SDSLOT_VDD 109 printk("%s: Disabling SD slot power\n", __func__); 110#endif 111 config_gpio_table(sdcard_off_gpio_table, 112 ARRAY_SIZE(sdcard_off_gpio_table)); 113 vreg_disable(vreg_sdslot); 114 sdslot_vreg_enabled = 0; 115 return 0; 116 } 117 118 if (!sdslot_vreg_enabled) { 119 rc = vreg_enable(vreg_sdslot); 120 if (rc) { 121 printk(KERN_ERR "%s: Error enabling vreg (%d)\n", 122 __func__, rc); 123 } 124 config_gpio_table(sdcard_on_gpio_table, 125 ARRAY_SIZE(sdcard_on_gpio_table)); 126 sdslot_vreg_enabled = 1; 127 } 128 129 for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) { 130 if (mmc_vdd_table[i].mask == (1 << vdd)) { 131#if DEBUG_SDSLOT_VDD 132 printk("%s: Setting level to %u\n", 133 __func__, mmc_vdd_table[i].level); 134#endif 135 rc = vreg_set_level(vreg_sdslot, 136 mmc_vdd_table[i].level); 137 if (rc) { 138 printk(KERN_ERR 139 "%s: Error setting vreg level (%d)\n", 140 __func__, rc); 141 } 142 return 0; 143 } 144 } 145 146 printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd); 147 return 0; 148} 149 150static unsigned int trout_sdslot_status(struct device *dev) 151{ 152 unsigned int status; 153 154 status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N); 155 return (!status); 156} 157 158#define TROUT_MMC_VDD MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \ 159 | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \ 160 | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \ 161 | MMC_VDD_28_29 | MMC_VDD_29_30 162 163static struct msm_mmc_platform_data trout_sdslot_data = { 164 .ocr_mask = TROUT_MMC_VDD, 165 .status = trout_sdslot_status, 166 .translate_vdd = trout_sdslot_switchvdd, 167}; 168 169int __init trout_init_mmc(unsigned int sys_rev) 170{ 171 sdslot_vreg_enabled = 0; 172 173 vreg_sdslot = vreg_get(0, "gp6"); 174 if (IS_ERR(vreg_sdslot)) 175 return PTR_ERR(vreg_sdslot); 176 177 set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1); 178 179 if (!opt_disable_sdcard) 180 msm_add_sdcc(2, &trout_sdslot_data, 181 TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0); 182 else 183 printk(KERN_INFO "trout: SD-Card interface disabled\n"); 184 return 0; 185} 186