This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM5728: MMC card detect issue

Part Number: AM5728
Other Parts Discussed in Thread: TMDSEVM572X

Tool/software: Linux

int mmc_of_parse(struct mmc_host *host)
{
 struct device *dev = host->parent;
 u32 bus_width;
 int ret;
 bool cd_cap_invert, cd_gpio_invert = false;
 bool ro_cap_invert, ro_gpio_invert = false;

 if (!dev || !dev_fwnode(dev))
  return 0;

 /* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
 if (device_property_read_u32(dev, "bus-width", &bus_width) < 0) {
  dev_dbg(host->parent,
   "\"bus-width\" property is missing, assuming 1 bit.\n");
  bus_width = 1;
 }

 switch (bus_width) {
 case 8:
  host->caps |= MMC_CAP_8_BIT_DATA;
  /* Hosts capable of 8-bit transfers can also do 4 bits */
 case 4:
  host->caps |= MMC_CAP_4_BIT_DATA;
  break;
 case 1:
  break;
 default:
  dev_err(host->parent,
   "Invalid \"bus-width\" value %u!\n", bus_width);
  return -EINVAL;
 }

 /* f_max is obtained from the optional "max-frequency" property */
 device_property_read_u32(dev, "max-frequency", &host->f_max);

 /*
  * Configure CD and WP pins. They are both by default active low to
  * match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
  * mmc-gpio helpers are used to attach, configure and use them. If
  * polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH
  * and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the
  * "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability
  * is set. If the "non-removable" property is found, the
  * MMC_CAP_NONREMOVABLE capability is set and no card-detection
  * configuration is performed.
  */

 /* Parse Card Detection */
 if (device_property_read_bool(dev, "non-removable")) {
  host->caps |= MMC_CAP_NONREMOVABLE;
 } else {
  cd_cap_invert = device_property_read_bool(dev, "cd-inverted");

  if (device_property_read_bool(dev, "broken-cd"))
   host->caps |= MMC_CAP_NEEDS_POLL;

  ret = mmc_gpiod_request_cd(host, "cd", 0, true,
        0, &cd_gpio_invert);
  if (!ret)
   dev_info(host->parent, "Got CD GPIO\n");
  else if (ret != -ENOENT && ret != -ENOSYS)
   return ret;

  /*
   * There are two ways to flag that the CD line is inverted:
   * through the cd-inverted flag and by the GPIO line itself
   * being inverted from the GPIO subsystem. This is a leftover
   * from the times when the GPIO subsystem did not make it
   * possible to flag a line as inverted.
   *
   * If the capability on the host AND the GPIO line are
   * both inverted, the end result is that the CD line is
   * not inverted.
   */
  if (cd_cap_invert ^ cd_gpio_invert)
   host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
 }

 /* Parse Write Protection */
 ro_cap_invert = device_property_read_bool(dev, "wp-inverted");

 ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
 if (!ret)
  dev_info(host->parent, "Got WP GPIO\n");
 else if (ret != -ENOENT && ret != -ENOSYS)
  return ret;

 if (device_property_read_bool(dev, "disable-wp"))
  host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;

 /* See the comment on CD inversion above */
 if (ro_cap_invert ^ ro_gpio_invert)
  host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;

 if (device_property_read_bool(dev, "cap-sd-highspeed"))
  host->caps |= MMC_CAP_SD_HIGHSPEED;
 if (device_property_read_bool(dev, "cap-mmc-highspeed"))
  host->caps |= MMC_CAP_MMC_HIGHSPEED;
 if (device_property_read_bool(dev, "sd-uhs-sdr12"))
  host->caps |= MMC_CAP_UHS_SDR12;
 if (device_property_read_bool(dev, "sd-uhs-sdr25"))
  host->caps |= MMC_CAP_UHS_SDR25;
 if (device_property_read_bool(dev, "sd-uhs-sdr50"))
  host->caps |= MMC_CAP_UHS_SDR50;
 if (device_property_read_bool(dev, "sd-uhs-sdr104"))
  host->caps |= MMC_CAP_UHS_SDR104;
 if (device_property_read_bool(dev, "sd-uhs-ddr50"))
  host->caps |= MMC_CAP_UHS_DDR50;
 if (device_property_read_bool(dev, "cap-power-off-card"))
  host->caps |= MMC_CAP_POWER_OFF_CARD;
 if (device_property_read_bool(dev, "cap-mmc-hw-reset"))
  host->caps |= MMC_CAP_HW_RESET;
 if (device_property_read_bool(dev, "cap-sdio-irq"))
  host->caps |= MMC_CAP_SDIO_IRQ;
 if (device_property_read_bool(dev, "full-pwr-cycle"))
  host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
 if (device_property_read_bool(dev, "keep-power-in-suspend"))
  host->pm_caps |= MMC_PM_KEEP_POWER;
 if (device_property_read_bool(dev, "wakeup-source") ||
     device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
  host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
 if (device_property_read_bool(dev, "mmc-ddr-3_3v"))
  host->caps |= MMC_CAP_3_3V_DDR;
 if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
  host->caps |= MMC_CAP_1_8V_DDR;
 if (device_property_read_bool(dev, "mmc-ddr-1_2v"))
  host->caps |= MMC_CAP_1_2V_DDR;
 if (device_property_read_bool(dev, "mmc-hs200-1_8v"))
  host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
 if (device_property_read_bool(dev, "mmc-hs200-1_2v"))
  host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
 if (device_property_read_bool(dev, "mmc-hs400-1_8v"))
  host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
 if (device_property_read_bool(dev, "mmc-hs400-1_2v"))
  host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
 if (device_property_read_bool(dev, "mmc-hs400-enhanced-strobe"))
  host->caps2 |= MMC_CAP2_HS400_ES;
 if (device_property_read_bool(dev, "no-sdio"))
  host->caps2 |= MMC_CAP2_NO_SDIO;
 if (device_property_read_bool(dev, "no-sd"))
  host->caps2 |= MMC_CAP2_NO_SD;
 if (device_property_read_bool(dev, "no-mmc"))
  host->caps2 |= MMC_CAP2_NO_MMC;

 host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
 if (host->dsr_req && (host->dsr & ~0xffff)) {
  dev_err(host->parent,
   "device tree specified broken value for DSR: 0x%x, ignoring\n",
   host->dsr);
  host->dsr_req = 0;
 }

 return mmc_pwrseq_alloc(host);
}

EXPORT_SYMBOL(mmc_of_parse);

Here are DTS section with mmc1

mmc@4809c000 {
   compatible = "ti,dra7-hsmmc", "ti,omap4-hsmmc";
   reg = <0x4809c000 0x00000400>;
   interrupts = <0x00000000 0x0000004e 0x00000004>;
   ti,hwmods = "mmc1";
   ti,dual-volt;
   ti,needs-special-reset;
   dmas = <0x000000b3 0x0000003d 0x000000b3 0x0000003e>;
   dma-names = "tx", "rx";
   status = "okay";
   pbias-supply = <0x000000cf>;
   sd-uhs-sdr104;
   sd-uhs-sdr50;
   sd-uhs-ddr50;
   sd-uhs-sdr25;
   sd-uhs-sdr12;
   pinctrl-names = "default", "hs", "sdr12", "sdr25", "sdr50", "ddr50", "sdr104";
   pinctrl-0 = <0x000000d0>;
   bus-width = <0x00000004>;
   cd-gpios = <0x000000d1 0x0000001b 0x00000001>;
   pinctrl-1 = <0x000000d2>;
   pinctrl-2 = <0x000000d3>;
   pinctrl-3 = <0x000000d4>;
   pinctrl-4 = <0x000000d5>;
   pinctrl-5 = <0x000000d6 0x000000d7>;
   pinctrl-6 = <0x000000d8 0x000000d9>;
   vmmc-supply = <0x000000cd>;
   vmmc_aux-supply = <0x000000da>;
  };

  • Hi Chuntian,

    Do you use AM57x TI PSDK v4.03 (link below)? If not, what SW do you use?

    software-dl.ti.com/.../index_FDS.html

    Do you use AM572x TI board or custom board?

    Do you use MMC card detect pin or GPIO pin?

    Regards,
    Pavel
  • Chuntian,

    Note that AM572x TI EVM TMDSEVM572X is using pin W7 (signal mmc1_sdcd) in gpio6_27 mode. This cd-gpios feature is supported by default in AM57x TI PSDK v4.03, no need to change MMC driver, only DTS file adjustment is needed. See for example how AM572x TI EVM MMC1 card detect with gpio pin is described in DTS:

    am57xx-beagle-x15-common.dtsi

    &mmc1 {
    status = "okay";

    pinctrl-names = "default";
    pinctrl-0 = <&mmc1_pins_default>;

    bus-width = <4>;
    cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
    };

    Regards,
    Pavel