cregit-Linux how code gets into the kernel

Release 4.11 drivers/mmc/host/sdhci-sirf.c

Directory: drivers/mmc/host
/*
 * SDHCI support for SiRF primaII and marco SoCs
 *
 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
 *
 * Licensed under GPLv2 or later.
 */

#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include "sdhci-pltfm.h"


#define SDHCI_CLK_DELAY_SETTING 0x4C

#define SDHCI_SIRF_8BITBUS BIT(3)

#define SIRF_TUNING_COUNT 16384


struct sdhci_sirf_priv {
	
int gpio_cd;
};


static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width) { u8 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~(SDHCI_CTRL_4BITBUS | SDHCI_SIRF_8BITBUS); /* * CSR atlas7 and prima2 SD host version is not 3.0 * 8bit-width enable bit of CSR SD hosts is 3, * while stardard hosts use bit 5 */ if (width == MMC_BUS_WIDTH_8) ctrl |= SDHCI_SIRF_8BITBUS; else if (width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }

Contributors

PersonTokensPropCommitsCommitProp
Minda Chen66100.00%1100.00%
Total66100.00%1100.00%


static u32 sdhci_sirf_readl_le(struct sdhci_host *host, int reg) { u32 val = readl(host->ioaddr + reg); if (unlikely((reg == SDHCI_CAPABILITIES_1) && (host->mmc->caps & MMC_CAP_UHS_SDR50))) { /* fake CAP_1 register */ val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING; } if (unlikely(reg == SDHCI_SLOT_INT_STATUS)) { u32 prss = val; /* fake chips as V3.0 host conreoller */ prss &= ~(0xFF << 16); val = prss | (SDHCI_SPEC_300 << 16); } return val; }

Contributors

PersonTokensPropCommitsCommitProp
Weijun Yang97100.00%2100.00%
Total97100.00%2100.00%


static u16 sdhci_sirf_readw_le(struct sdhci_host *host, int reg) { u16 ret = 0; ret = readw(host->ioaddr + reg); if (unlikely(reg == SDHCI_HOST_VERSION)) { ret = readw(host->ioaddr + SDHCI_HOST_VERSION); ret |= SDHCI_SPEC_300; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Weijun Yang59100.00%1100.00%
Total59100.00%1100.00%


static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; int phase; u8 tuned_phase_cnt = 0; int rc = 0, longest_range = 0; int start = -1, end = 0, tuning_value = -1, range = 0; u16 clock_setting; struct mmc_host *mmc = host->mmc; clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING); clock_setting &= ~0x3fff; retry: phase = 0; tuned_phase_cnt = 0; do { sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); if (!mmc_send_tuning(mmc, opcode, NULL)) { /* Tuning is successful at this tuning point */ tuned_phase_cnt++; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", mmc_hostname(mmc), phase); if (start == -1) start = phase; end = phase; range++; if (phase == (SIRF_TUNING_COUNT - 1) && range > longest_range) tuning_value = (start + end) / 2; } else { dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n", mmc_hostname(mmc), phase); if (range > longest_range) { tuning_value = (start + end) / 2; longest_range = range; } start = -1; end = range = 0; } } while (++phase < SIRF_TUNING_COUNT); if (tuned_phase_cnt && tuning_value > 0) { /* * Finally set the selected phase in delay * line hw block. */ phase = tuning_value; sdhci_writel(host, clock_setting | phase, SDHCI_CLK_DELAY_SETTING); dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { if (--tuning_seq_cnt) goto retry; /* Tuning failed */ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n", mmc_hostname(mmc)); rc = -EIO; } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Minda Chen30996.26%125.00%
Weijun Yang82.49%250.00%
Chaotian Jing41.25%125.00%
Total321100.00%4100.00%

static struct sdhci_ops sdhci_sirf_ops = { .read_l = sdhci_sirf_readl_le, .read_w = sdhci_sirf_readw_le, .platform_execute_tuning = sdhci_sirf_execute_tuning, .set_clock = sdhci_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .set_bus_width = sdhci_sirf_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, }; static struct sdhci_pltfm_data sdhci_sirf_pdata = { .ops = &sdhci_sirf_ops, .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, };
static int sdhci_sirf_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_sirf_priv *priv; struct clk *clk; int gpio_cd; int ret; clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "unable to get clock"); return PTR_ERR(clk); } if (pdev->dev.of_node) gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0); else gpio_cd = -EINVAL; host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); pltfm_host->clk = clk; priv = sdhci_pltfm_priv(pltfm_host); priv->gpio_cd = gpio_cd; sdhci_get_of_property(pdev); ret = clk_prepare_enable(pltfm_host->clk); if (ret) goto err_clk_prepare; ret = sdhci_add_host(host); if (ret) goto err_sdhci_add; /* * We must request the IRQ after sdhci_add_host(), as the tasklet only * gets setup in sdhci_add_host() and we oops. */ if (gpio_is_valid(priv->gpio_cd)) { ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0); if (ret) { dev_err(&pdev->dev, "card detect irq request failed: %d\n", ret); goto err_request_cd; } mmc_gpiod_request_cd_irq(host->mmc); } return 0; err_request_cd: sdhci_remove_host(host, 0); err_sdhci_add: clk_disable_unprepare(pltfm_host->clk); err_clk_prepare: sdhci_pltfm_free(pdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Barry Song22580.65%120.00%
Arnd Bergmann3713.26%120.00%
Kevin Hao82.87%120.00%
Stephen Warren72.51%120.00%
Laurent Pinchart20.72%120.00%
Total279100.00%5100.00%

#ifdef CONFIG_PM_SLEEP
static int sdhci_sirf_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); int ret; ret = sdhci_suspend_host(host); if (ret) return ret; clk_disable(pltfm_host->clk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Barry Song5798.28%150.00%
Kevin Hao11.72%150.00%
Total58100.00%2100.00%


static int sdhci_sirf_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); int ret; ret = clk_enable(pltfm_host->clk); if (ret) { dev_dbg(dev, "Resume: Error enabling clock\n"); return ret; } return sdhci_resume_host(host); }

Contributors

PersonTokensPropCommitsCommitProp
Barry Song6498.46%150.00%
Kevin Hao11.54%150.00%
Total65100.00%2100.00%

#endif static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume); static const struct of_device_id sdhci_sirf_of_match[] = { { .compatible = "sirf,prima2-sdhc" }, { } }; MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match); static struct platform_driver sdhci_sirf_driver = { .driver = { .name = "sdhci-sirf", .of_match_table = sdhci_sirf_of_match, .pm = &sdhci_sirf_pm_ops, }, .probe = sdhci_sirf_probe, .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_sirf_driver); MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco"); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
Barry Song51344.07%210.53%
Minda Chen39233.68%210.53%
Weijun Yang17515.03%421.05%
Arnd Bergmann373.18%15.26%
Russell King191.63%421.05%
Kevin Hao121.03%210.53%
Stephen Warren70.60%15.26%
Chaotian Jing40.34%15.26%
Ulf Hansson30.26%15.26%
Laurent Pinchart20.17%15.26%
Total1164100.00%19100.00%
Directory: drivers/mmc/host
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.