blob: 9ad229594b46e2f2c259d2e549d7c61525319e10 [file] [log] [blame]
Tony Lindgren90c62bf2008-12-10 17:37:17 -08001/*
Adrian Hunterd02a900b2010-02-15 10:03:34 -08002 * linux/arch/arm/mach-omap2/hsmmc.c
Tony Lindgren90c62bf2008-12-10 17:37:17 -08003 *
4 * Copyright (C) 2007-2008 Texas Instruments
5 * Copyright (C) 2008 Nokia Corporation
6 * Author: Texas Instruments
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080012#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/string.h>
Tony Lindgren90c62bf2008-12-10 17:37:17 -080015#include <linux/delay.h>
Tony Lindgren90c62bf2008-12-10 17:37:17 -080016#include <mach/hardware.h>
Tony Lindgrence491cf2009-10-20 09:40:47 -070017#include <plat/control.h>
18#include <plat/mmc.h>
Adrian Huntere3df0fb2010-02-15 10:03:34 -080019#include <plat/omap-pm.h>
Tony Lindgren90c62bf2008-12-10 17:37:17 -080020
Adrian Hunterd02a900b2010-02-15 10:03:34 -080021#include "hsmmc.h"
Tony Lindgren90c62bf2008-12-10 17:37:17 -080022
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080023#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
Tony Lindgren90c62bf2008-12-10 17:37:17 -080024
Tony Lindgren90c62bf2008-12-10 17:37:17 -080025static u16 control_pbias_offset;
26static u16 control_devconf1_offset;
27
28#define HSMMC_NAME_LEN 9
29
Adrian Hunter68ff0422010-02-15 10:03:34 -080030static struct hsmmc_controller {
David Brownellb583f262009-05-28 14:04:03 -070031 char name[HSMMC_NAME_LEN + 1];
32} hsmmc[OMAP34XX_NR_MMC];
Tony Lindgren90c62bf2008-12-10 17:37:17 -080033
Denis Karpov1887bde2009-09-22 16:44:40 -070034#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
35
Adrian Hunter68ff0422010-02-15 10:03:34 -080036static int hsmmc_get_context_loss(struct device *dev)
Denis Karpov1887bde2009-09-22 16:44:40 -070037{
Adrian Huntere3df0fb2010-02-15 10:03:34 -080038 return omap_pm_get_dev_context_loss_count(dev);
Denis Karpov1887bde2009-09-22 16:44:40 -070039}
40
41#else
Adrian Hunter68ff0422010-02-15 10:03:34 -080042#define hsmmc_get_context_loss NULL
Denis Karpov1887bde2009-09-22 16:44:40 -070043#endif
44
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080045static void hsmmc1_before_set_reg(struct device *dev, int slot,
46 int power_on, int vdd)
Tony Lindgren90c62bf2008-12-10 17:37:17 -080047{
Madhu555d5032009-11-22 10:11:08 -080048 u32 reg, prog_io;
Tony Lindgren90c62bf2008-12-10 17:37:17 -080049 struct omap_mmc_platform_data *mmc = dev->platform_data;
50
Adrian Hunterce6f0012010-02-15 10:03:34 -080051 if (mmc->slots[0].remux)
52 mmc->slots[0].remux(dev, slot, power_on);
53
David Brownell0329c372009-03-23 18:23:47 -070054 /*
55 * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
David Brownellb583f262009-05-28 14:04:03 -070056 * card with Vcc regulator (from twl4030 or whatever). OMAP has both
David Brownell0329c372009-03-23 18:23:47 -070057 * 1.8V and 3.0V modes, controlled by the PBIAS register.
58 *
59 * In 8-bit modes, OMAP VMMC1A (for DAT4..7) needs a supply, which
60 * is most naturally TWL VSIM; those pins also use PBIAS.
David Brownellb583f262009-05-28 14:04:03 -070061 *
62 * FIXME handle VMMC1A as needed ...
David Brownell0329c372009-03-23 18:23:47 -070063 */
Tony Lindgren90c62bf2008-12-10 17:37:17 -080064 if (power_on) {
65 if (cpu_is_omap2430()) {
66 reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1);
67 if ((1 << vdd) >= MMC_VDD_30_31)
68 reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE;
69 else
70 reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE;
71 omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1);
72 }
73
74 if (mmc->slots[0].internal_clock) {
75 reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
76 reg |= OMAP2_MMCSDIO1ADPCLKISEL;
77 omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0);
78 }
79
80 reg = omap_ctrl_readl(control_pbias_offset);
Madhu555d5032009-11-22 10:11:08 -080081 if (cpu_is_omap3630()) {
82 /* Set MMC I/O to 52Mhz */
83 prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
84 prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
85 omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
86 } else {
87 reg |= OMAP2_PBIASSPEEDCTRL0;
88 }
Tony Lindgren90c62bf2008-12-10 17:37:17 -080089 reg &= ~OMAP2_PBIASLITEPWRDNZ0;
90 omap_ctrl_writel(reg, control_pbias_offset);
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080091 } else {
92 reg = omap_ctrl_readl(control_pbias_offset);
93 reg &= ~OMAP2_PBIASLITEPWRDNZ0;
94 omap_ctrl_writel(reg, control_pbias_offset);
95 }
96}
Tony Lindgren90c62bf2008-12-10 17:37:17 -080097
Adrian Hunterdb0fefc2010-02-15 10:03:34 -080098static void hsmmc1_after_set_reg(struct device *dev, int slot,
99 int power_on, int vdd)
100{
101 u32 reg;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800102
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800103 /* 100ms delay required for PBIAS configuration */
104 msleep(100);
105
106 if (power_on) {
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800107 reg = omap_ctrl_readl(control_pbias_offset);
108 reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
109 if ((1 << vdd) <= MMC_VDD_165_195)
110 reg &= ~OMAP2_PBIASLITEVMODE0;
111 else
112 reg |= OMAP2_PBIASLITEVMODE0;
113 omap_ctrl_writel(reg, control_pbias_offset);
114 } else {
115 reg = omap_ctrl_readl(control_pbias_offset);
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800116 reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
117 OMAP2_PBIASLITEVMODE0);
118 omap_ctrl_writel(reg, control_pbias_offset);
119 }
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800120}
121
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800122static void hsmmc23_before_set_reg(struct device *dev, int slot,
123 int power_on, int vdd)
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800124{
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800125 struct omap_mmc_platform_data *mmc = dev->platform_data;
Grazvydas Ignotas762ad3a42009-06-23 13:30:22 +0300126
Adrian Hunterce6f0012010-02-15 10:03:34 -0800127 if (mmc->slots[0].remux)
128 mmc->slots[0].remux(dev, slot, power_on);
129
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800130 if (power_on) {
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800131 /* Only MMC2 supports a CLKIN */
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800132 if (mmc->slots[0].internal_clock) {
133 u32 reg;
134
135 reg = omap_ctrl_readl(control_devconf1_offset);
136 reg |= OMAP2_MMCSDIO2ADPCLKISEL;
137 omap_ctrl_writel(reg, control_devconf1_offset);
138 }
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800139 }
Adrian Hunter9b7c18e2009-09-22 16:44:50 -0700140}
141
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800142static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
143
Adrian Hunter68ff0422010-02-15 10:03:34 -0800144void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800145{
Adrian Hunter68ff0422010-02-15 10:03:34 -0800146 struct omap2_hsmmc_info *c;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800147 int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
Aaro Koskinena6c7fdd2010-02-04 13:06:59 +0200148 int i;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800149
150 if (cpu_is_omap2430()) {
151 control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
152 control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800153 } else {
154 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
155 control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
156 }
157
158 for (c = controllers; c->mmc; c++) {
Adrian Hunter68ff0422010-02-15 10:03:34 -0800159 struct hsmmc_controller *hc = hsmmc + c->mmc - 1;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800160 struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
161
162 if (!c->mmc || c->mmc > nr_hsmmc) {
163 pr_debug("MMC%d: no such controller\n", c->mmc);
164 continue;
165 }
166 if (mmc) {
167 pr_debug("MMC%d: already configured\n", c->mmc);
168 continue;
169 }
170
Adrian Hunter68ff0422010-02-15 10:03:34 -0800171 mmc = kzalloc(sizeof(struct omap_mmc_platform_data),
172 GFP_KERNEL);
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800173 if (!mmc) {
174 pr_err("Cannot allocate memory for mmc device!\n");
Aaro Koskinena6c7fdd2010-02-04 13:06:59 +0200175 goto done;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800176 }
177
Adrian Huntere51151a2009-03-23 18:23:48 -0700178 if (c->name)
Adrian Hunter68ff0422010-02-15 10:03:34 -0800179 strncpy(hc->name, c->name, HSMMC_NAME_LEN);
Adrian Huntere51151a2009-03-23 18:23:48 -0700180 else
Adrian Hunter68ff0422010-02-15 10:03:34 -0800181 snprintf(hc->name, ARRAY_SIZE(hc->name),
Adrian Huntere51151a2009-03-23 18:23:48 -0700182 "mmc%islot%i", c->mmc, 1);
Adrian Hunter68ff0422010-02-15 10:03:34 -0800183 mmc->slots[0].name = hc->name;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800184 mmc->nr_slots = 1;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800185 mmc->slots[0].wires = c->wires;
186 mmc->slots[0].internal_clock = !c->ext_clock;
187 mmc->dma_mask = 0xffffffff;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800188
Adrian Hunter68ff0422010-02-15 10:03:34 -0800189 mmc->get_context_loss_count = hsmmc_get_context_loss;
Denis Karpov1887bde2009-09-22 16:44:40 -0700190
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800191 mmc->slots[0].switch_pin = c->gpio_cd;
192 mmc->slots[0].gpio_wp = c->gpio_wp;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800193
Adrian Hunterce6f0012010-02-15 10:03:34 -0800194 mmc->slots[0].remux = c->remux;
195
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800196 if (c->cover_only)
197 mmc->slots[0].cover = 1;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800198
Adrian Hunter23d99bb2009-09-22 16:44:48 -0700199 if (c->nonremovable)
200 mmc->slots[0].nonremovable = 1;
201
Denis Karpovdd498ef2009-09-22 16:44:49 -0700202 if (c->power_saving)
203 mmc->slots[0].power_saving = 1;
204
Adrian Hunter1df58db2010-02-15 10:03:34 -0800205 if (c->no_off)
206 mmc->slots[0].no_off = 1;
207
Adrian Huntere0eb2422010-02-15 10:03:34 -0800208 if (c->vcc_aux_disable_is_sleep)
209 mmc->slots[0].vcc_aux_disable_is_sleep = 1;
210
David Brownellb583f262009-05-28 14:04:03 -0700211 /* NOTE: MMC slots should have a Vcc regulator set up.
212 * This may be from a TWL4030-family chip, another
213 * controllable regulator, or a fixed supply.
214 *
215 * temporary HACK: ocr_mask instead of fixed supply
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800216 */
David Brownellb583f262009-05-28 14:04:03 -0700217 mmc->slots[0].ocr_mask = c->ocr_mask;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800218
219 switch (c->mmc) {
220 case 1:
David Brownellb583f262009-05-28 14:04:03 -0700221 /* on-chip level shifting via PBIAS0/PBIAS1 */
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800222 mmc->slots[0].before_set_reg = hsmmc1_before_set_reg;
223 mmc->slots[0].after_set_reg = hsmmc1_after_set_reg;
Madhu41fd03d2009-11-22 10:11:07 -0800224
225 /* Omap3630 HSMMC1 supports only 4-bit */
226 if (cpu_is_omap3630() && c->wires > 4) {
227 c->wires = 4;
228 mmc->slots[0].wires = c->wires;
229 }
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800230 break;
231 case 2:
David Brownellb583f262009-05-28 14:04:03 -0700232 if (c->ext_clock)
233 c->transceiver = 1;
234 if (c->transceiver && c->wires > 4)
235 c->wires = 4;
236 /* FALLTHROUGH */
Grazvydas Ignotas07d83cc2009-03-23 18:23:47 -0700237 case 3:
David Brownellb583f262009-05-28 14:04:03 -0700238 /* off-chip level shifting, or none */
Adrian Hunterdb0fefc2010-02-15 10:03:34 -0800239 mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
240 mmc->slots[0].after_set_reg = NULL;
Grazvydas Ignotas07d83cc2009-03-23 18:23:47 -0700241 break;
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800242 default:
243 pr_err("MMC%d configuration not supported!\n", c->mmc);
Grazvydas Ignotas07d83cc2009-03-23 18:23:47 -0700244 kfree(mmc);
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800245 continue;
246 }
247 hsmmc_data[c->mmc - 1] = mmc;
248 }
249
250 omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
David Brownell01971f62009-03-23 18:23:47 -0700251
252 /* pass the device nodes back to board setup code */
253 for (c = controllers; c->mmc; c++) {
254 struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
255
256 if (!c->mmc || c->mmc > nr_hsmmc)
257 continue;
258 c->dev = mmc->dev;
259 }
Aaro Koskinena6c7fdd2010-02-04 13:06:59 +0200260
261done:
262 for (i = 0; i < nr_hsmmc; i++)
263 kfree(hsmmc_data[i]);
Tony Lindgren90c62bf2008-12-10 17:37:17 -0800264}
265
266#endif