Merge branch 'msm-sdcc' into for-next

* msm-sdcc:
  msm: 8x50: Add initial support for SDCC
  mmc: msm_sdcc: Add gpio handling function to driver
  drivers: mmc: msm: remove clock disable in probe
  mmc: msm: fix dma usage not to use internal APIs
This commit is contained in:
David Brown 2011-01-24 15:42:46 -08:00
commit 14847fdf35
7 changed files with 376 additions and 36 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -31,6 +32,8 @@
#include <mach/irqs.h>
#include <mach/sirc.h>
#include <mach/gpio.h>
#include <mach/vreg.h>
#include <mach/mmc.h>
#include "devices.h"
@ -95,6 +98,81 @@ static struct platform_device *devices[] __initdata = {
&msm_device_hsusb_host,
};
static struct msm_mmc_gpio sdc1_gpio_cfg[] = {
{51, "sdc1_dat_3"},
{52, "sdc1_dat_2"},
{53, "sdc1_dat_1"},
{54, "sdc1_dat_0"},
{55, "sdc1_cmd"},
{56, "sdc1_clk"}
};
static struct vreg *vreg_mmc;
static unsigned long vreg_sts;
static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
{
int rc = 0;
struct platform_device *pdev;
pdev = container_of(dv, struct platform_device, dev);
if (vdd == 0) {
if (!vreg_sts)
return 0;
clear_bit(pdev->id, &vreg_sts);
if (!vreg_sts) {
rc = vreg_disable(vreg_mmc);
if (rc)
pr_err("vreg_mmc disable failed for slot "
"%d: %d\n", pdev->id, rc);
}
return 0;
}
if (!vreg_sts) {
rc = vreg_set_level(vreg_mmc, 2900);
if (rc)
pr_err("vreg_mmc set level failed for slot %d: %d\n",
pdev->id, rc);
rc = vreg_enable(vreg_mmc);
if (rc)
pr_err("vreg_mmc enable failed for slot %d: %d\n",
pdev->id, rc);
}
set_bit(pdev->id, &vreg_sts);
return 0;
}
static struct msm_mmc_gpio_data sdc1_gpio = {
.gpio = sdc1_gpio_cfg,
.size = ARRAY_SIZE(sdc1_gpio_cfg),
};
static struct msm_mmc_platform_data qsd8x50_sdc1_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
.translate_vdd = msm_sdcc_setup_power,
.gpio_data = &sdc1_gpio,
};
static void __init qsd8x50_init_mmc(void)
{
if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa())
vreg_mmc = vreg_get(NULL, "gp6");
else
vreg_mmc = vreg_get(NULL, "gp5");
if (IS_ERR(vreg_mmc)) {
pr_err("vreg get for vreg_mmc failed (%ld)\n",
PTR_ERR(vreg_mmc));
return;
}
msm_add_sdcc(1, &qsd8x50_sdc1_data, 0, 0);
}
static void __init qsd8x50_map_io(void)
{
msm_map_qsd8x50_io();
@ -113,6 +191,7 @@ static void __init qsd8x50_init(void)
msm_device_hsusb.dev.parent = &msm_device_otg.dev;
msm_device_hsusb_host.dev.parent = &msm_device_otg.dev;
platform_add_devices(devices, ARRAY_SIZE(devices));
qsd8x50_init_mmc();
}
MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")

View file

@ -125,6 +125,194 @@ struct platform_device msm_device_hsusb_host = {
},
};
static struct resource resources_sdc1[] = {
{
.start = MSM_SDC1_PHYS,
.end = MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
.start = INT_SDC1_0,
.end = INT_SDC1_0,
.flags = IORESOURCE_IRQ,
.name = "cmd_irq",
},
{
.start = INT_SDC1_1,
.end = INT_SDC1_1,
.flags = IORESOURCE_IRQ,
.name = "pio_irq",
},
{
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
.name = "status_irq"
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_DMA,
},
};
static struct resource resources_sdc2[] = {
{
.start = MSM_SDC2_PHYS,
.end = MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
.start = INT_SDC2_0,
.end = INT_SDC2_0,
.flags = IORESOURCE_IRQ,
.name = "cmd_irq",
},
{
.start = INT_SDC2_1,
.end = INT_SDC2_1,
.flags = IORESOURCE_IRQ,
.name = "pio_irq",
},
{
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
.name = "status_irq"
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_DMA,
},
};
static struct resource resources_sdc3[] = {
{
.start = MSM_SDC3_PHYS,
.end = MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
.start = INT_SDC3_0,
.end = INT_SDC3_0,
.flags = IORESOURCE_IRQ,
.name = "cmd_irq",
},
{
.start = INT_SDC3_1,
.end = INT_SDC3_1,
.flags = IORESOURCE_IRQ,
.name = "pio_irq",
},
{
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
.name = "status_irq"
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_DMA,
},
};
static struct resource resources_sdc4[] = {
{
.start = MSM_SDC4_PHYS,
.end = MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
.start = INT_SDC4_0,
.end = INT_SDC4_0,
.flags = IORESOURCE_IRQ,
.name = "cmd_irq",
},
{
.start = INT_SDC4_1,
.end = INT_SDC4_1,
.flags = IORESOURCE_IRQ,
.name = "pio_irq",
},
{
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
.name = "status_irq"
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_DMA,
},
};
struct platform_device msm_device_sdc1 = {
.name = "msm_sdcc",
.id = 1,
.num_resources = ARRAY_SIZE(resources_sdc1),
.resource = resources_sdc1,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
};
struct platform_device msm_device_sdc2 = {
.name = "msm_sdcc",
.id = 2,
.num_resources = ARRAY_SIZE(resources_sdc2),
.resource = resources_sdc2,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
};
struct platform_device msm_device_sdc3 = {
.name = "msm_sdcc",
.id = 3,
.num_resources = ARRAY_SIZE(resources_sdc3),
.resource = resources_sdc3,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
};
struct platform_device msm_device_sdc4 = {
.name = "msm_sdcc",
.id = 4,
.num_resources = ARRAY_SIZE(resources_sdc4),
.resource = resources_sdc4,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
};
static struct platform_device *msm_sdcc_devices[] __initdata = {
&msm_device_sdc1,
&msm_device_sdc2,
&msm_device_sdc3,
&msm_device_sdc4,
};
int __init msm_add_sdcc(unsigned int controller,
struct msm_mmc_platform_data *plat,
unsigned int stat_irq, unsigned long stat_irq_flags)
{
struct platform_device *pdev;
struct resource *res;
if (controller < 1 || controller > 4)
return -EINVAL;
pdev = msm_sdcc_devices[controller-1];
pdev->dev.platform_data = plat;
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq");
if (!res)
return -EINVAL;
else if (stat_irq) {
res->start = res->end = stat_irq;
res->flags &= ~IORESOURCE_DISABLED;
res->flags |= stat_irq_flags;
}
return platform_device_register(pdev);
}
struct clk msm_clocks_8x50[] = {
CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN),
@ -145,6 +333,14 @@ struct clk msm_clocks_8x50[] = {
CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN),
CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0),
CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF),
CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF),
CLK_PCOM("sdc_pclk", SDC1_P_CLK, &msm_device_sdc1.dev, OFF),
CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
CLK_PCOM("sdc_pclk", SDC2_P_CLK, &msm_device_sdc2.dev, OFF),
CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
CLK_PCOM("sdc_pclk", SDC3_P_CLK, &msm_device_sdc3.dev, OFF),
CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
CLK_PCOM("sdc_pclk", SDC4_P_CLK, &msm_device_sdc4.dev, OFF),
CLK_PCOM("spi_clk", SPI_CLK, NULL, 0),
CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0),
CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0),

View file

@ -16,6 +16,19 @@
*/
#include "gpiomux.h"
#if defined(CONFIG_MMC_MSM) || defined(CONFIG_MMC_MSM_MODULE)
#define SDCC_DAT_0_3_CMD_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_UP\
| GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
#define SDCC_CLK_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_NONE\
| GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
#else
#define SDCC_DAT_0_3_CMD_ACTV_CFG 0
#define SDCC_CLK_ACTV_CFG 0
#endif
#define SDC1_SUSPEND_CONFIG (GPIOMUX_VALID | GPIOMUX_PULL_DOWN\
| GPIOMUX_FUNC_GPIO | GPIOMUX_DRV_2MA)
struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
[86] = { /* UART3 RX */
.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
@ -25,4 +38,14 @@ struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
GPIOMUX_FUNC_1 | GPIOMUX_VALID,
},
/* SDC1 data[3:0] & CMD */
[51 ... 55] = {
.active = SDCC_DAT_0_3_CMD_ACTV_CFG,
.suspended = SDC1_SUSPEND_CONFIG
},
/* SDC1 CLK */
[56] = {
.active = SDCC_CLK_ACTV_CFG,
.suspended = SDC1_SUSPEND_CONFIG
},
};

View file

@ -15,12 +15,23 @@ struct embedded_sdio_data {
int num_funcs;
};
struct msm_mmc_gpio {
unsigned no;
const char *name;
};
struct msm_mmc_gpio_data {
struct msm_mmc_gpio *gpio;
u8 size;
};
struct msm_mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
u32 (*translate_vdd)(struct device *, unsigned int);
unsigned int (*status)(struct device *);
struct embedded_sdio_data *embedded_sdio;
int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
struct msm_mmc_gpio_data *gpio_data;
};
#endif

View file

@ -124,16 +124,16 @@
#define MSM_UART2DM_PHYS 0xA0900000
#define MSM_SDC1_PHYS 0xA0400000
#define MSM_SDC1_PHYS 0xA0300000
#define MSM_SDC1_SIZE SZ_4K
#define MSM_SDC2_PHYS 0xA0500000
#define MSM_SDC2_PHYS 0xA0400000
#define MSM_SDC2_SIZE SZ_4K
#define MSM_SDC3_PHYS 0xA0600000
#define MSM_SDC3_PHYS 0xA0500000
#define MSM_SDC3_SIZE SZ_4K
#define MSM_SDC4_PHYS 0xA0700000
#define MSM_SDC4_PHYS 0xA0600000
#define MSM_SDC4_SIZE SZ_4K
#endif

View file

@ -36,6 +36,7 @@
#include <linux/io.h>
#include <linux/memory.h>
#include <linux/gfp.h>
#include <linux/gpio.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
@ -383,14 +384,30 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
host->curr.user_pages = 0;
box = &nc->cmd[0];
for (i = 0; i < host->dma.num_ents; i++) {
/* location of command block must be 64 bit aligned */
BUG_ON(host->dma.cmd_busaddr & 0x07);
nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
host->dma.num_ents, host->dma.dir);
if (n == 0) {
printk(KERN_ERR "%s: Unable to map in all sg elements\n",
mmc_hostname(host->mmc));
host->dma.sg = NULL;
host->dma.num_ents = 0;
return -ENOMEM;
}
for_each_sg(host->dma.sg, sg, n, i) {
box->cmd = CMD_MODE_BOX;
/* Initialize sg dma address */
sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
+ sg->offset;
if (i == (host->dma.num_ents - 1))
if (i == n - 1)
box->cmd |= CMD_LC;
rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
(sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
@ -418,27 +435,6 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
box->cmd |= CMD_DST_CRCI(crci);
}
box++;
sg++;
}
/* location of command block must be 64 bit aligned */
BUG_ON(host->dma.cmd_busaddr & 0x07);
nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
host->dma.num_ents, host->dma.dir);
/* dsb inside dma_map_sg will write nc out to mem as well */
if (n != host->dma.num_ents) {
printk(KERN_ERR "%s: Unable to map in all sg elements\n",
mmc_hostname(host->mmc));
host->dma.sg = NULL;
host->dma.num_ents = 0;
return -ENOMEM;
}
return 0;
@ -946,6 +942,38 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock_irqrestore(&host->lock, flags);
}
static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
{
struct msm_mmc_gpio_data *curr;
int i, rc = 0;
if (!host->plat->gpio_data && host->gpio_config_status == enable)
return;
curr = host->plat->gpio_data;
for (i = 0; i < curr->size; i++) {
if (enable) {
rc = gpio_request(curr->gpio[i].no,
curr->gpio[i].name);
if (rc) {
pr_err("%s: gpio_request(%d, %s) failed %d\n",
mmc_hostname(host->mmc),
curr->gpio[i].no,
curr->gpio[i].name, rc);
goto free_gpios;
}
} else {
gpio_free(curr->gpio[i].no);
}
}
host->gpio_config_status = enable;
return;
free_gpios:
for (; i >= 0; i--)
gpio_free(curr->gpio[i].no);
}
static void
msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
@ -958,6 +986,8 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
msmsdcc_enable_clocks(host);
spin_unlock_irqrestore(&host->lock, flags);
if (ios->clock) {
if (ios->clock != host->clk_rate) {
rc = clk_set_rate(host->clk, ios->clock);
@ -984,9 +1014,11 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
msmsdcc_setup_gpio(host, false);
break;
case MMC_POWER_UP:
pwr |= MCI_PWR_UP;
msmsdcc_setup_gpio(host, true);
break;
case MMC_POWER_ON:
pwr |= MCI_PWR_ON;
@ -1003,9 +1035,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
msmsdcc_writel(host, pwr, MMCIPOWER);
}
#if BUSCLK_PWRSAVE
spin_lock_irqsave(&host->lock, flags);
msmsdcc_disable_clocks(host, 1);
#endif
spin_unlock_irqrestore(&host->lock, flags);
#endif
}
static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
@ -1331,9 +1364,6 @@ msmsdcc_probe(struct platform_device *pdev)
if (host->timer.function)
pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
#if BUSCLK_PWRSAVE
msmsdcc_disable_clocks(host, 1);
#endif
return 0;
cmd_irq_free:
free_irq(cmd_irqres->start, host);

View file

@ -243,6 +243,7 @@ struct msmsdcc_host {
unsigned int cmd_datactrl;
struct mmc_command *cmd_cmd;
u32 cmd_c;
bool gpio_config_status;
bool prog_scan;
bool prog_enable;