コード例 #1
0
static inline void sunximmc_resume_pins(struct sunxi_mmc_host* smc_host)
{
    int ret;
    u32 i;

    SMC_DBG("mmc %d resume pins\n", smc_host->pdev->id);
    switch(smc_host->pdev->id)
    {
        case 0:
        case 1:
        case 2:
        case 3:
            /* restore gpios' backup configuration */
            if (smc_host->gpio_suspend_ok)
            {
                smc_host->gpio_suspend_ok = 0;
                for (i=0; i<6; i++)
                {
                    ret = gpio_set_one_pin_status(smc_host->pio_hdle, &smc_host->bak_gpios[i], smc_host->bak_gpios[i].gpio_name, 1);
                    if (ret)
                    {
                        SMC_ERR("fail to restore IO(%s) to resume status\n", smc_host->bak_gpios[i].gpio_name);
                    }
                }
            }

            break;
    }
}
コード例 #2
0
/* static s32 sunximmc_set_src_clk(struct sunxi_mmc_host* smc_host)
 * 设置SD卡控制器源时钟频率, 目标为100MHz,clock源有smc_host的clk_source决定
 * clk_source: 0-video PLL, 2-dram PLL, 3-core pll
 */
static int sunximmc_set_src_clk(struct sunxi_mmc_host* smc_host)
{
    struct clk *source_clock = NULL;
    char* name[] = {"hosc", "sata_pll_2", "sdram_pll_p", "hosc"};
    int ret;

    switch (smc_host->clk_source)
    {
        case 0:
        case 3:
            source_clock = clk_get(&smc_host->pdev->dev, "hosc");
            break;
        case 1:
            source_clock = clk_get(&smc_host->pdev->dev, "sata_pll_2");
            break;
        case 2:
            source_clock = clk_get(&smc_host->pdev->dev, "sdram_pll_p");
            break;
    }
    if (IS_ERR(source_clock))
    {
    	ret = PTR_ERR(source_clock);
    	SMC_ERR("Error to get source clock %s\n", name[smc_host->clk_source]);
    	return ret;
    }

    clk_set_parent(smc_host->mclk, source_clock);
    clk_set_rate(smc_host->mclk, smc_host->mod_clk);
    clk_enable(smc_host->mclk);
    
    #ifdef CONFIG_SUN5I_FPGA
    smc_host->mod_clk = 24000000;
    #else
    smc_host->mod_clk = clk_get_rate(smc_host->mclk);
    #endif
    clk_enable(smc_host->hclk);

    SMC_INFO("smc %d, source = %s, src_clk = %u, mclk %u, \n", smc_host->pdev->id, name[smc_host->clk_source], (unsigned)clk_get_rate(source_clock), smc_host->mod_clk);
    clk_put(source_clock);

    return 0;
}
コード例 #3
0
static int __init sunximmc_init(void)
{
    int ret;
    int i;
    char mmc_para[16] = {0};
    int used = 0;

    SMC_MSG("sunximmc_init\n");
    for (i=0; i<SUNXI_MMC_HOST_NUM; i++)
    {
        memset(mmc_para, 0, sizeof(mmc_para));
        sprintf(mmc_para, "mmc%d_para", i);
        used = 0;

        ret = script_parser_fetch(mmc_para,"sdc_used", &used, sizeof(int));
        if (ret)
        {
        	printk("sunximmc_init fetch mmc%d using configuration failed\n", i);
        }

        if (used)
        {
            sdc_used |= 1 << i;
            platform_device_register(&awmmc_device[i]);
        }

    }

    SMC_MSG("sunxi mmc controller using config : 0x%x\n", sdc_used);

    if (sdc_used)
    {
        return platform_driver_register(&sunximmc_driver);
    }
    else
    {
        SMC_ERR("cannot find any using configuration for controllers, return directly!\n");
        return 0;
    }
}
コード例 #4
0
static s32 sunximmc_get_ro(struct mmc_host *mmc)
{
    struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
    char mmc_para[16] = {0};
    int card_wp = 0;
    int ret;
    u32 gpio_val;

    sprintf(mmc_para, "mmc%d_para", smc_host->pdev->id);
    ret = script_parser_fetch(mmc_para, "sdc_use_wp", &card_wp, sizeof(int));
    if (ret)
    {
    	SMC_ERR("sdc fetch card write protect mode failed\n");
    }
    if (card_wp)
    {
        gpio_val = gpio_read_one_pin_value(smc_host->pio_hdle, "sdc_wp");
        SMC_DBG("sdc fetch card write protect pin status val = %d \n", gpio_val);
        if (!gpio_val)
        {
            smc_host->read_only = 0;
            return 0;
        }
        else
        {
            SMC_MSG("Card is write-protected\n");
            smc_host->read_only = 1;
            return 1;
        }
    }
    else
    {
        smc_host->read_only = 0;
        return 0;
    }
}
コード例 #5
0
static int sunximmc_resource_request(struct sunxi_mmc_host *smc_host)
{
    struct platform_device *pdev = smc_host->pdev;
    u32 smc_no = pdev->id;
    char hclk_name[16] = {0};
    char mclk_name[8] = {0};
    char pio_para[16] = {0};
    u32 pio_hdle = 0;
    s32 ret = 0;

    sprintf(pio_para, "mmc%d_para", smc_no);
    pio_hdle = gpio_request_ex(pio_para, NULL);
    if (!pio_hdle)
    {
        SMC_ERR("sdc %d request pio parameter failed\n", smc_no);
        goto out;
    }
    smc_host->pio_hdle = pio_hdle;

    //iomap
    smc_host->smc_base_res  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!smc_host->smc_base_res)
    {
    	SMC_ERR("Failed to get io memory region resouce.\n");

    	ret = -ENOENT;
    	goto release_pin;
    }
    /* smc address remap */
    smc_host->smc_base_res = request_mem_region(smc_host->smc_base_res->start, RESSIZE(smc_host->smc_base_res), pdev->name);
    if (!smc_host->smc_base_res)
    {
    	SMC_ERR("Failed to request io memory region.\n");
    	ret = -ENOENT;
    	goto release_pin;
    }
    smc_host->smc_base = ioremap(smc_host->smc_base_res->start, RESSIZE(smc_host->smc_base_res));
    if (!smc_host->smc_base)
    {
    	SMC_ERR("Failed to ioremap() io memory region.\n");
    	ret = -EINVAL;
    	goto free_mem_region;
    }

    //get hclock
    sprintf(hclk_name, "ahb_sdc%d", smc_no);
    smc_host->hclk = clk_get(&pdev->dev, hclk_name);
    if (IS_ERR(smc_host->hclk))
    {
    	ret = PTR_ERR(smc_host->hclk);
    	SMC_ERR("Error to get ahb clk for %s\n", hclk_name);
    	goto iounmap;
    }

    sprintf(mclk_name, "sdc%d", smc_no);
    smc_host->mclk = clk_get(&pdev->dev, mclk_name);
    if (IS_ERR(smc_host->mclk))
    {
    	ret = PTR_ERR(smc_host->mclk);
    	SMC_ERR("Error to get clk for mux_mmc\n");
    	goto free_hclk;
    }

    goto out;

free_hclk:
    clk_put(smc_host->hclk);

iounmap:
    iounmap(smc_host->smc_base);

free_mem_region:
    release_mem_region(smc_host->smc_base_res->start, RESSIZE(smc_host->smc_base_res));

release_pin:
    gpio_release(smc_host->pio_hdle, 1);

out:
    return ret;
}
コード例 #6
0
static int __devinit sunximmc_probe(struct platform_device *pdev)
{
    struct sunxi_mmc_host *smc_host = NULL;
    struct mmc_host	*mmc = NULL;
    int ret = 0;
    char mmc_para[16] = {0};
    int card_detmode = 0;

    SMC_MSG("%s: pdev->name: %s, pdev->id: %d\n", dev_name(&pdev->dev), pdev->name, pdev->id);
    mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
    if (!mmc)
    {
        SMC_ERR("mmc alloc host failed\n");
    	ret = -ENOMEM;
    	goto probe_out;
    }

    smc_host = mmc_priv(mmc);
    memset((void*)smc_host, 0, sizeof(smc_host));
    smc_host->mmc = mmc;
    smc_host->pdev = pdev;

    spin_lock_init(&smc_host->lock);
    tasklet_init(&smc_host->tasklet, sunximmc_tasklet, (unsigned long) smc_host);

    smc_host->cclk  = 400000;
    smc_host->mod_clk = SMC_MAX_MOD_CLOCK(pdev->id);
    smc_host->clk_source = SMC_MOD_CLK_SRC(pdev->id);

    mmc->ops        = &sunximmc_ops;
    mmc->ocr_avail	= MMC_VDD_32_33 | MMC_VDD_33_34;
    mmc->caps	    = MMC_CAP_4_BIT_DATA|MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED|MMC_CAP_SDIO_IRQ;
    mmc->f_min 	    = 400000;
    mmc->f_max      = SMC_MAX_IO_CLOCK(pdev->id);
#ifdef MMC_PM_IGNORE_PM_NOTIFY
    if (pdev->id==3 && !mmc_pm_io_shd_suspend_host())
        mmc->pm_flags = MMC_PM_IGNORE_PM_NOTIFY;
#endif

    mmc->max_blk_count	= 4095;
    mmc->max_blk_size	= 4095;
    mmc->max_req_size	= 4095 * 512;              //32bit byte counter = 2^32 - 1
    mmc->max_seg_size	= mmc->max_req_size;
    mmc->max_segs	    = 256;

    if (sunximmc_resource_request(smc_host))
    {
        SMC_ERR("%s: Failed to get resouce.\n", dev_name(&pdev->dev));
        goto probe_free_host;
    }

    if (sunximmc_set_src_clk(smc_host))
    {
        goto probe_free_host;
    }
    sunximmc_init_controller(smc_host);
    smc_host->power_on = 1;
    sunximmc_procfs_attach(smc_host);

    /* irq */
    smc_host->irq = platform_get_irq(pdev, 0);
    if (smc_host->irq == 0)
    {
    	dev_err(&pdev->dev, "Failed to get interrupt resouce.\n");
    	ret = -EINVAL;
    	goto probe_free_resource;
    }

    if (request_irq(smc_host->irq, sunximmc_irq, 0, DRIVER_NAME, smc_host))
    {
    	dev_err(&pdev->dev, "Failed to request smc card interrupt.\n");
    	ret = -ENOENT;
    	goto probe_free_irq;
    }
    disable_irq(smc_host->irq);

    /* add host */
    ret = mmc_add_host(mmc);
    if (ret)
    {
    	dev_err(&pdev->dev, "Failed to add mmc host.\n");
    	goto probe_free_irq;
    }
    platform_set_drvdata(pdev, mmc);

    //fetch card detecetd mode
    sprintf(mmc_para, "mmc%d_para", pdev->id);
    ret = script_parser_fetch(mmc_para, "sdc_detmode", &card_detmode, sizeof(int));
    if (ret)
    {
    	SMC_ERR("sdc fetch card detect mode failed\n");
    }

    smc_host->cd_mode = card_detmode;
    if (smc_host->cd_mode == CARD_DETECT_BY_GPIO)
    {
        //initial card detect timer
        init_timer(&smc_host->cd_timer);
        smc_host->cd_timer.expires = jiffies + 1*HZ;
        smc_host->cd_timer.function = &sunximmc_cd_timer;
        smc_host->cd_timer.data = (unsigned long)smc_host;
        add_timer(&smc_host->cd_timer);
        smc_host->present = 0;
    }

    enable_irq(smc_host->irq);

	mutex_lock(&sw_host_rescan_mutex);
	if (smc_host->cd_mode == CARD_ALWAYS_PRESENT ||
	    sw_host_rescan_pending[pdev->id]) {
		smc_host->present = 1;
        mmc_detect_change(smc_host->mmc, msecs_to_jiffies(300));
    }

    sw_host[pdev->id] = smc_host;
	mutex_unlock(&sw_host_rescan_mutex);

    SMC_MSG("mmc%d Probe: base:0x%p irq:%u dma:%u pdes:0x%p, ret %d.\n",
            pdev->id, smc_host->smc_base, smc_host->irq, smc_host->dma_no, smc_host->pdes, ret);

    goto probe_out;

probe_free_irq:
    if (smc_host->irq)
    {
        free_irq(smc_host->irq, smc_host);
    }

probe_free_resource:
    sunximmc_resource_release(smc_host);

probe_free_host:
    mmc_free_host(mmc);

probe_out:
    return ret;
}
コード例 #7
0
static void sunximmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
    struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
    s32 ret = -1;

    /* Set the power state */
    switch (ios->power_mode)
    {
        case MMC_POWER_ON:
        case MMC_POWER_UP:
            if (!smc_host->power_on)
            {
                SMC_MSG("mmc %d power on !!\n", smc_host->pdev->id);
                /* resume pins to correct status */
                sunximmc_resume_pins(smc_host);
            	/* enable mmc hclk */
            	clk_enable(smc_host->hclk);
            	/* enable mmc mclk */
            	clk_enable(smc_host->mclk);
                /* restore registers */
                sdxc_regs_restore(smc_host);
                sdxc_program_clk(smc_host);
                /* enable irq */
                enable_irq(smc_host->irq);
                smc_host->power_on = 1;
            }
        	break;
        case MMC_POWER_OFF:
            if (smc_host->power_on)
            {
                SMC_MSG("mmc %d power off !!\n", smc_host->pdev->id);
                /* disable irq */
                disable_irq(smc_host->irq);
                /* backup registers */
                sdxc_regs_save(smc_host);
            	/* disable mmc mclk */
            	clk_disable(smc_host->mclk);
            	/* disable mmc hclk */
            	clk_disable(smc_host->hclk);
                /* suspend pins to save power */
                sunximmc_suspend_pins(smc_host);
                smc_host->power_on = 0;
                smc_host->ferror = 0;
            }
        default:
        	break;
    }

    /* set clock */
    if (smc_host->power_on)
    {
        /* set clock */
        if (ios->clock)
        {
            smc_host->cclk = ios->clock;
            ret = sdxc_update_clk(smc_host, smc_host->mod_clk, smc_host->cclk);
            if (ret == -1) {
                SMC_ERR("Fatal error, please check your pin configuration.\n");
                smc_host->ferror = 1;
            }
            if ((ios->power_mode == MMC_POWER_ON) || (ios->power_mode == MMC_POWER_UP))
            {
            	SMC_DBG("running at %dkHz (requested: %dkHz).\n", smc_host->real_cclk/1000, ios->clock/1000);
            }
            else
            {
            	SMC_DBG("powered down.\n");
            }
        }

        /* set bus width */
        if (smc_host->bus_width != (1<<ios->bus_width))
        {
            sdxc_set_buswidth(smc_host, 1<<ios->bus_width);
            smc_host->bus_width = 1<<ios->bus_width;
        }
    }
}
コード例 #8
0
static inline void sunximmc_suspend_pins(struct sunxi_mmc_host* smc_host)
{
    int ret;
    user_gpio_set_t suspend_gpio_set = {"suspend_pins_sdio", 0, 0, 0, 2, 1, 0};     //for sdio
    user_gpio_set_t suspend_gpio_set_card = {"suspend_pins_mmc", 0, 0, 0, 0, 1, 0};    //for mmc card
    u32 i;

    SMC_DBG("mmc %d suspend pins\n", smc_host->pdev->id);
    /* backup gpios' current config */
    ret = gpio_get_all_pin_status(smc_host->pio_hdle, smc_host->bak_gpios, 6, 1);
    if (ret)
    {
        SMC_ERR("fail to fetch current gpio cofiguration\n");
        return;
    }

//    {
//        SMC_MSG("printk backup gpio configuration: \n");
//        for (i=0; i<6; i++)
//        {
//            SMC_MSG("gpio[%d]: name %s, port %c[%d], cfg %d, pull %d, drvl %d, data %d\n",
//                         i, smc_host->bak_gpios[i].gpio_name,
//                            smc_host->bak_gpios[i].port + 'A' - 1,
//                            smc_host->bak_gpios[i].port_num,
//                            smc_host->bak_gpios[i].mul_sel,
//                            smc_host->bak_gpios[i].pull,
//                            smc_host->bak_gpios[i].drv_level,
//                            smc_host->bak_gpios[i].data);
//        }
//    }

    switch(smc_host->pdev->id)
    {
        case 0:
        case 1:
        case 2:
            /* setup all pins to input and no pull to save power */
            for (i=0; i<6; i++)
            {
                ret = gpio_set_one_pin_status(smc_host->pio_hdle, &suspend_gpio_set_card, smc_host->bak_gpios[i].gpio_name, 1);
                if (ret)
                {
                    SMC_ERR("fail to set IO(%s) into suspend status\n", smc_host->bak_gpios[i].gpio_name);
                }
            }
            break;
        case 3:
            /* setup all pins to input and pulldown to save power */
            for (i=0; i<6; i++)
            {
                ret = gpio_set_one_pin_status(smc_host->pio_hdle, &suspend_gpio_set, smc_host->bak_gpios[i].gpio_name, 1);
                if (ret)
                {
                    SMC_ERR("fail to set IO(%s) into suspend status\n", smc_host->bak_gpios[i].gpio_name);
                }
            }
            break;
    }

//    {
//        user_gpio_set_t post_cfg[6];
//
//        gpio_get_all_pin_status(smc_host->pio_hdle, post_cfg, 6, 1);
//        for (i=0; i<6; i++)
//        {
//            SMC_MSG("post suspend, gpio[%d]: name %s, port %c[%d], cfg %d, pull %d, drvl %d, data %d\n",
//                         i, post_cfg[i].gpio_name,
//                            post_cfg[i].port + 'A' - 1,
//                            post_cfg[i].port_num,
//                            post_cfg[i].mul_sel,
//                            post_cfg[i].pull,
//                            post_cfg[i].drv_level,
//                            post_cfg[i].data);
//        }
//    }

    smc_host->gpio_suspend_ok = 1;
    return;
}