+
+#ifdef CONFIG_IODELAY_RECALIBRATION
+static struct pad_conf_entry *
+omap_hsmmc_get_pad_conf_entry(const fdt32_t *pinctrl, int count)
+{
+ int index = 0;
+ struct pad_conf_entry *padconf;
+
+ padconf = (struct pad_conf_entry *)malloc(sizeof(*padconf) * count);
+ if (!padconf) {
+ debug("failed to allocate memory\n");
+ return 0;
+ }
+
+ while (index < count) {
+ padconf[index].offset = fdt32_to_cpu(pinctrl[2 * index]);
+ padconf[index].val = fdt32_to_cpu(pinctrl[2 * index + 1]);
+ index++;
+ }
+
+ return padconf;
+}
+
+static struct iodelay_cfg_entry *
+omap_hsmmc_get_iodelay_cfg_entry(const fdt32_t *pinctrl, int count)
+{
+ int index = 0;
+ struct iodelay_cfg_entry *iodelay;
+
+ iodelay = (struct iodelay_cfg_entry *)malloc(sizeof(*iodelay) * count);
+ if (!iodelay) {
+ debug("failed to allocate memory\n");
+ return 0;
+ }
+
+ while (index < count) {
+ iodelay[index].offset = fdt32_to_cpu(pinctrl[3 * index]);
+ iodelay[index].a_delay = fdt32_to_cpu(pinctrl[3 * index + 1]);
+ iodelay[index].g_delay = fdt32_to_cpu(pinctrl[3 * index + 2]);
+ index++;
+ }
+
+ return iodelay;
+}
+
+static const fdt32_t *omap_hsmmc_get_pinctrl_entry(u32 phandle,
+ const char *name, int *len)
+{
+ const void *fdt = gd->fdt_blob;
+ int offset;
+ const fdt32_t *pinctrl;
+
+ offset = fdt_node_offset_by_phandle(fdt, phandle);
+ if (offset < 0) {
+ debug("failed to get pinctrl node %s.\n",
+ fdt_strerror(offset));
+ return 0;
+ }
+
+ pinctrl = fdt_getprop(fdt, offset, name, len);
+ if (!pinctrl) {
+ debug("failed to get property %s\n", name);
+ return 0;
+ }
+
+ return pinctrl;
+}
+
+static uint32_t omap_hsmmc_get_pad_conf_phandle(struct mmc *mmc,
+ char *prop_name)
+{
+ const void *fdt = gd->fdt_blob;
+ const __be32 *phandle;
+ int node = dev_of_offset(mmc->dev);
+
+ phandle = fdt_getprop(fdt, node, prop_name, NULL);
+ if (!phandle) {
+ debug("failed to get property %s\n", prop_name);
+ return 0;
+ }
+
+ return fdt32_to_cpu(*phandle);
+}
+
+static uint32_t omap_hsmmc_get_iodelay_phandle(struct mmc *mmc,
+ char *prop_name)
+{
+ const void *fdt = gd->fdt_blob;
+ const __be32 *phandle;
+ int len;
+ int count;
+ int node = dev_of_offset(mmc->dev);
+
+ phandle = fdt_getprop(fdt, node, prop_name, &len);
+ if (!phandle) {
+ debug("failed to get property %s\n", prop_name);
+ return 0;
+ }
+
+ /* No manual mode iodelay values if count < 2 */
+ count = len / sizeof(*phandle);
+ if (count < 2)
+ return 0;
+
+ return fdt32_to_cpu(*(phandle + 1));
+}
+
+static struct pad_conf_entry *
+omap_hsmmc_get_pad_conf(struct mmc *mmc, char *prop_name, int *npads)
+{
+ int len;
+ int count;
+ struct pad_conf_entry *padconf;
+ u32 phandle;
+ const fdt32_t *pinctrl;
+
+ phandle = omap_hsmmc_get_pad_conf_phandle(mmc, prop_name);
+ if (!phandle)
+ return ERR_PTR(-EINVAL);
+
+ pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-single,pins",
+ &len);
+ if (!pinctrl)
+ return ERR_PTR(-EINVAL);
+
+ count = (len / sizeof(*pinctrl)) / 2;
+ padconf = omap_hsmmc_get_pad_conf_entry(pinctrl, count);
+ if (!padconf)
+ return ERR_PTR(-EINVAL);
+
+ *npads = count;
+
+ return padconf;
+}
+
+static struct iodelay_cfg_entry *
+omap_hsmmc_get_iodelay(struct mmc *mmc, char *prop_name, int *niodelay)
+{
+ int len;
+ int count;
+ struct iodelay_cfg_entry *iodelay;
+ u32 phandle;
+ const fdt32_t *pinctrl;
+
+ phandle = omap_hsmmc_get_iodelay_phandle(mmc, prop_name);
+ /* Not all modes have manual mode iodelay values. So its not fatal */
+ if (!phandle)
+ return 0;
+
+ pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-pin-array",
+ &len);
+ if (!pinctrl)
+ return ERR_PTR(-EINVAL);
+
+ count = (len / sizeof(*pinctrl)) / 3;
+ iodelay = omap_hsmmc_get_iodelay_cfg_entry(pinctrl, count);
+ if (!iodelay)
+ return ERR_PTR(-EINVAL);
+
+ *niodelay = count;
+
+ return iodelay;
+}
+
+static struct omap_hsmmc_pinctrl_state *
+omap_hsmmc_get_pinctrl_by_mode(struct mmc *mmc, char *mode)
+{
+ int index;
+ int npads = 0;
+ int niodelays = 0;
+ const void *fdt = gd->fdt_blob;
+ int node = dev_of_offset(mmc->dev);
+ char prop_name[11];
+ struct omap_hsmmc_pinctrl_state *pinctrl_state;
+
+ pinctrl_state = (struct omap_hsmmc_pinctrl_state *)
+ malloc(sizeof(*pinctrl_state));
+ if (!pinctrl_state) {
+ debug("failed to allocate memory\n");
+ return 0;
+ }
+
+ index = fdt_stringlist_search(fdt, node, "pinctrl-names", mode);
+ if (index < 0) {
+ debug("fail to find %s mode %s\n", mode, fdt_strerror(index));
+ goto err_pinctrl_state;
+ }
+
+ sprintf(prop_name, "pinctrl-%d", index);
+
+ pinctrl_state->padconf = omap_hsmmc_get_pad_conf(mmc, prop_name,
+ &npads);
+ if (IS_ERR(pinctrl_state->padconf))
+ goto err_pinctrl_state;
+ pinctrl_state->npads = npads;
+
+ pinctrl_state->iodelay = omap_hsmmc_get_iodelay(mmc, prop_name,
+ &niodelays);
+ if (IS_ERR(pinctrl_state->iodelay))
+ goto err_padconf;
+ pinctrl_state->niodelays = niodelays;
+
+ return pinctrl_state;
+
+err_padconf:
+ kfree(pinctrl_state->padconf);
+
+err_pinctrl_state:
+ kfree(pinctrl_state);
+ return 0;
+}
+
+#define OMAP_HSMMC_SETUP_PINCTRL(capmask, mode) \
+ do { \
+ struct omap_hsmmc_pinctrl_state *s; \
+ if (!(cfg->host_caps & capmask)) \
+ break; \
+ \
+ s = omap_hsmmc_get_pinctrl_by_mode(mmc, #mode); \
+ if (!s) { \
+ debug("%s: no pinctrl for %s\n", \
+ mmc->dev->name, #mode); \
+ cfg->host_caps &= ~(capmask); \
+ } else { \
+ priv->mode##_pinctrl_state = s; \
+ } \
+ } while (0)
+
+static int omap_hsmmc_get_pinctrl_state(struct mmc *mmc)
+{
+ struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+ struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
+ struct omap_hsmmc_pinctrl_state *default_pinctrl;
+
+ if (!(priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY))
+ return 0;
+
+ default_pinctrl = omap_hsmmc_get_pinctrl_by_mode(mmc, "default");
+ if (!default_pinctrl) {
+ printf("no pinctrl state for default mode\n");
+ return -EINVAL;
+ }
+
+ priv->default_pinctrl_state = default_pinctrl;
+
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR104), sdr104);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR50), sdr50);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_DDR50), ddr50);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR25), sdr25);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR12), sdr12);
+
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_HS_200), hs200_1_8v);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_DDR_52), ddr_1_8v);
+ OMAP_HSMMC_SETUP_PINCTRL(MMC_MODE_HS, hs);
+
+ return 0;
+}
+#endif
+