diff mbox

[1/2] Add OF binding helpers for MMC drivers

Message ID 20110421131957.GB15194@dandreoli.com (mailing list archive)
State New, archived
Headers show

Commit Message

Domenico Andreoli April 21, 2011, 1:19 p.m. UTC
From: Domenico Andreoli <cavokz@gmail.com>

This patch adds helpers to manage OF binding of MMC DeviceTree configs.
They don't cover all the MMC configuration cases, indeed are only a
slight generalization of those found in the MMC-over-SPI driver. More
will come later.

Signed-off-by: Domenico Andreoli <cavokz@gmail.com>
---
 drivers/of/Kconfig     |    4 +
 drivers/of/Makefile    |    1 +
 drivers/of/of_mmc.c    |  165 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_mmc.h |   50 +++++++++++++++
 4 files changed, 220 insertions(+)

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Grant Likely April 21, 2011, 2:14 p.m. UTC | #1
On Thu, Apr 21, 2011 at 03:19:57PM +0200, Domenico Andreoli wrote:
> From: Domenico Andreoli <cavokz@gmail.com>
> 
> This patch adds helpers to manage OF binding of MMC DeviceTree configs.
> They don't cover all the MMC configuration cases, indeed are only a
> slight generalization of those found in the MMC-over-SPI driver. More
> will come later.

Can the mmc-over-spi driver be generalized to use this code too?

> 
> Signed-off-by: Domenico Andreoli <cavokz@gmail.com>
> ---
>  drivers/of/Kconfig     |    4 +
>  drivers/of/Makefile    |    1 +
>  drivers/of/of_mmc.c    |  165 +++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/of_mmc.h |   50 +++++++++++++++

Personally I think it makes more sense for this code to live in drivers/mmc/core.

>  4 files changed, 220 insertions(+)
> 
> Index: b/drivers/of/Kconfig
> ===================================================================
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -59,6 +59,10 @@ config OF_I2C
>  	help
>  	  OpenFirmware I2C accessors
>  
> +config OF_MMC
> +	depends on MMC
> +	def_bool y
> +
>  config OF_NET
>  	depends on NETDEVICES
>  	def_bool y
> Index: b/drivers/of/Makefile
> ===================================================================
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_OF_DEVICE) += device.o plat
>  obj-$(CONFIG_OF_GPIO)   += gpio.o
>  obj-$(CONFIG_OF_CLOCK)	+= clock.o
>  obj-$(CONFIG_OF_I2C)	+= of_i2c.o
> +obj-$(CONFIG_OF_MMC)	+= of_mmc.o
>  obj-$(CONFIG_OF_NET)	+= of_net.o
>  obj-$(CONFIG_OF_SPI)	+= of_spi.o
>  obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
> Index: b/drivers/of/of_mmc.c
> ===================================================================
> --- /dev/null
> +++ b/drivers/of/of_mmc.c
> @@ -0,0 +1,165 @@
> +/*
> + * OF helpers for the MMC API
> + *
> + * Copyright (c) 2011 Domenico Andreoli
> + *
> + * Heavily inspired by the OF support to the MMC-over-SPI driver made
> + * by Anton Vorontsov
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/mmc/core.h>
> +#include <linux/gpio.h>
> +#include <linux/of.h>
> +#include <linux/of_mmc.h>
> +#include <linux/of_gpio.h>
> +
> +static int of_read_mmc_gpio(struct of_mmc_crg *crg, int gpio_num)
> +{
> +	int value, active_low;
> +
> +	BUG_ON(gpio_num >= NUM_MMC_GPIOS);
> +
> +	/* hitting this means that DeviceTree left this gpio unspecified
> +	 * by purpose but driver didn't take any measure to define its
> +	 * behavior (i.e. aborting probe phase or disabling the feature).
> +	 * driver needs to call of_is_valid_mmc_crg() for each expected
> +	 * gpio to detect this case.
> +	 */
> +	if (WARN_ON(crg->gpios[gpio_num] < 0))
> +		return -1;
> +
> +	value = gpio_get_value(crg->gpios[gpio_num]);
> +	active_low = crg->alow_gpios[gpio_num];
> +	return value ^ active_low;
> +}
> +
> +int of_get_mmc_cd_gpio(struct of_mmc_crg *crg)
> +{
> +	return of_read_mmc_gpio(crg, CD_MMC_GPIO);
> +}
> +EXPORT_SYMBOL(of_get_mmc_cd_gpio);
> +
> +int of_get_mmc_ro_gpio(struct of_mmc_crg *crg)
> +{
> +	return of_read_mmc_gpio(crg, WP_MMC_GPIO);
> +}
> +EXPORT_SYMBOL(of_get_mmc_ro_gpio);
> +
> +int of_is_valid_mmc_crg(struct of_mmc_crg *crg, int gpio_num)
> +{
> +	BUG_ON(gpio_num >= NUM_MMC_GPIOS);
> +	return gpio_is_valid(crg->gpios[gpio_num]);
> +}
> +EXPORT_SYMBOL(of_is_valid_mmc_crg);
> +
> +int of_get_mmc_crg(struct device *dev, struct device_node *np,
> +                   int cd_off, struct of_mmc_crg *crg)
> +{
> +	int *gpio, *alow;
> +	int i, ret;
> +
> +	memset(crg, 0, sizeof(*crg));
> +	crg->cd_irq = -1;
> +
> +	gpio = crg->gpios;
> +	alow = crg->alow_gpios;
> +	for (i = 0; i < NUM_MMC_GPIOS; i++, gpio++, alow++) {
> +		enum of_gpio_flags gpio_flags;
> +		*gpio = of_get_gpio_flags(np, cd_off+i, &gpio_flags);
> +		*alow = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
> +
> +		if (*gpio == -EEXIST || *gpio == -ENOENT) {
> +			/* driver needs to define proper meaning of this missing
> +			   gpio (i.e. abort probe or disable the feature) */
> +			pr_debug("%s: gpio #%d is not specified\n", __func__, i);
> +			continue;
> +		}
> +		if (*gpio < 0) {
> +			pr_debug("%s: invalid configuration\n", __func__);
> +			ret = *gpio;
> +			break;
> +		}
> +		if (!gpio_is_valid(*gpio)) {
> +			pr_debug("%s: gpio #%d is not valid: %d\n", __func__, i, *gpio);
> +			ret = -EINVAL;
> +			break;
> +		}
> +		ret = gpio_request(*gpio, dev_name(dev));
> +		if (ret < 0) {
> +			pr_debug("%s: gpio #%d is not available: %d\n", __func__, i, *gpio);
> +			break;
> +		}
> +	}
> +
> +	if (i < NUM_MMC_GPIOS) {
> +		while (--gpio >= crg->gpios)
> +			if (gpio_is_valid(*gpio))
> +				gpio_free(*gpio);
> +		return ret;
> +	}
> +
> +	if (gpio_is_valid(crg->gpios[CD_MMC_GPIO])) {
> +		gpio_direction_input(crg->gpios[CD_MMC_GPIO]);
> +		crg->cd_irq = gpio_to_irq(crg->gpios[CD_MMC_GPIO]);
> +		if (crg->cd_irq < 0)
> +			pr_debug("%s: cannot get cd irq number\n", __func__);
> +	}
> +	if (gpio_is_valid(crg->gpios[WP_MMC_GPIO]))
> +		gpio_direction_input(crg->gpios[WP_MMC_GPIO]);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(of_get_mmc_crg);
> +
> +void of_put_mmc_crg(struct of_mmc_crg *crg)
> +{
> +	int i;
> +	for (i = 0; i < NUM_MMC_GPIOS; i++)
> +		if (gpio_is_valid(crg->gpios[i]))
> +			gpio_free(crg->gpios[i]);
> +}
> +EXPORT_SYMBOL(of_put_mmc_crg);
> +
> +u32 of_get_mmc_ocr_mask(struct device_node *np)
> +{
> +	const u32 *voltage_ranges;
> +	int num_ranges;
> +	u32 ocr_mask;
> +	int i, j;
> +
> +	voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
> +	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
> +	if (!voltage_ranges || !num_ranges) {
> +		pr_debug("%s: voltage-ranges unspecified\n", __func__);
> +		return 0;
> +	}
> +
> +	ocr_mask = 0;
> +	for (i = 0, j = 0; i < num_ranges; i++) {
> +		int vdd_min = be32_to_cpup(voltage_ranges++);
> +		int vdd_max = be32_to_cpup(voltage_ranges++);
> +		u32 mask = mmc_vddrange_to_ocrmask(vdd_min, vdd_max);
> +
> +		if (!mask) {
> +			pr_debug("%s: voltage-range #%d is invalid\n", __func__, i);
> +			return 0;
> +		}
> +		ocr_mask |= mask;
> +	}
> +
> +	return ocr_mask;
> +}
> +EXPORT_SYMBOL(of_get_mmc_ocr_mask);
> +
> +MODULE_AUTHOR("Domenico Andreoli <cavok@gmail.com>");
> +MODULE_LICENSE("GPL");
> Index: b/include/linux/of_mmc.h
> ===================================================================
> --- /dev/null
> +++ b/include/linux/of_mmc.h
> @@ -0,0 +1,50 @@
> +/*
> + * OF helpers for the MMC API
> + *
> + * Copyright (c) 2011 Domenico Andreoli
> + *
> + * Heavily inspired by the OF support to the MMC-over-SPI driver made
> + * by Anton Vorontsov
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#ifndef __LINUX_OF_MMC_H
> +#define __LINUX_OF_MMC_H
> +
> +#include <linux/of.h>
> +#include <linux/gpio.h>
> +
> +#ifdef CONFIG_OF_MMC
> +
> +enum {
> +	CD_MMC_GPIO = 0,
> +	WP_MMC_GPIO,
> +	NUM_MMC_GPIOS,
> +};
> +
> +/* Card detect and Read only Gpio data */
> +struct of_mmc_crg {
> +	int gpios[NUM_MMC_GPIOS];
> +	int alow_gpios[NUM_MMC_GPIOS];
> +	int cd_irq;
> +};

Many drivers currently provide this data via a platform_data.  It
would probably be more useful and require less code if both DT and
non-DT users shared the same structure for MMC gpios.  The structure
could both be embedded in pdata and populated by this DT parsing code.
It would also mean that each driver wouldn't need separate DT and
non-DT code for consuming the information.

> +
> +extern u32 of_get_mmc_ocr_mask(struct device_node *);
> +extern int of_get_mmc_crg(struct device *, struct device_node *,
> +                          int cd_off, struct of_mmc_crg *);
> +
> +/* if board does not use cd interrupts, driver can optimize polling
> +   using this function. */
> +extern int of_get_mmc_cd_gpio(struct of_mmc_crg *);
> +/* sense switch on sd cards */
> +extern int of_get_mmc_ro_gpio(struct of_mmc_crg *);
> +extern int of_is_valid_mmc_crg(struct of_mmc_crg *, int gpio_num);
> +extern void of_put_mmc_crg(struct of_mmc_crg *);
> +
> +#endif /* CONFIG_OF_MMC */
> +
> +#endif /* __LINUX_OF_MMC_H */
> 
> ------------------------------------------------------------------------------
> Benefiting from Server Virtualization: Beyond Initial Workload 
> Consolidation -- Increasing the use of server virtualization is a top
> priority.Virtualization can reduce costs, simplify management, and improve 
> application availability and disaster protection. Learn more about boosting 
> the value of server virtualization. http://p.sf.net/sfu/vmware-sfdev2dev
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Domenico Andreoli April 22, 2011, 9:02 a.m. UTC | #2
On Thu, Apr 21, 2011 at 4:14 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Thu, Apr 21, 2011 at 03:19:57PM +0200, Domenico Andreoli wrote:
>> From: Domenico Andreoli <cavokz@gmail.com>
>>
>> This patch adds helpers to manage OF binding of MMC DeviceTree configs.
>> They don't cover all the MMC configuration cases, indeed are only a
>> slight generalization of those found in the MMC-over-SPI driver. More
>> will come later.
>
> Can the mmc-over-spi driver be generalized to use this code too?

I made a mess with the patches... the second one of this set _is_ mmc-over-spi
converted to this generalization. Instead I sent GPIO OF stuff... sorry.

>> +/* Card detect and Read only Gpio data */
>> +struct of_mmc_crg {
>> +     int gpios[NUM_MMC_GPIOS];
>> +     int alow_gpios[NUM_MMC_GPIOS];
>> +     int cd_irq;
>> +};
>
> Many drivers currently provide this data via a platform_data.  It
> would probably be more useful and require less code if both DT and
> non-DT users shared the same structure for MMC gpios.  The structure
> could both be embedded in pdata and populated by this DT parsing code.
> It would also mean that each driver wouldn't need separate DT and
> non-DT code for consuming the information.

I agree, indeed I'm not able to use these helpers within the s3c-mmc driver
without duplicating and writing ugly code.

I made some "research" so I have few patches of tries which made me learn
a bit. There is not a common management of these as well as of the
set_power() callbacks, to say those I learned about looking at S3C MMC.

In practice also MMC platform datas require some consolidation.

Kgene, Ben, do you plan to work on the S3C MCI driver? Can I spend some
time on it without duplicating the effort of anybody?

Regards,
Domenico

-----[ Domenico Andreoli, aka cavok
 --[ http://cavokz.wordpress.com/gpgkey/
   ---[ 3A0F 2F80 F79C 678A 8936  4FEE 0677 9033 A20E BC50
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

Index: b/drivers/of/Kconfig
===================================================================
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -59,6 +59,10 @@  config OF_I2C
 	help
 	  OpenFirmware I2C accessors
 
+config OF_MMC
+	depends on MMC
+	def_bool y
+
 config OF_NET
 	depends on NETDEVICES
 	def_bool y
Index: b/drivers/of/Makefile
===================================================================
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -7,6 +7,7 @@  obj-$(CONFIG_OF_DEVICE) += device.o plat
 obj-$(CONFIG_OF_GPIO)   += gpio.o
 obj-$(CONFIG_OF_CLOCK)	+= clock.o
 obj-$(CONFIG_OF_I2C)	+= of_i2c.o
+obj-$(CONFIG_OF_MMC)	+= of_mmc.o
 obj-$(CONFIG_OF_NET)	+= of_net.o
 obj-$(CONFIG_OF_SPI)	+= of_spi.o
 obj-$(CONFIG_OF_MDIO)	+= of_mdio.o
Index: b/drivers/of/of_mmc.c
===================================================================
--- /dev/null
+++ b/drivers/of/of_mmc.c
@@ -0,0 +1,165 @@ 
+/*
+ * OF helpers for the MMC API
+ *
+ * Copyright (c) 2011 Domenico Andreoli
+ *
+ * Heavily inspired by the OF support to the MMC-over-SPI driver made
+ * by Anton Vorontsov
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mmc/core.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_mmc.h>
+#include <linux/of_gpio.h>
+
+static int of_read_mmc_gpio(struct of_mmc_crg *crg, int gpio_num)
+{
+	int value, active_low;
+
+	BUG_ON(gpio_num >= NUM_MMC_GPIOS);
+
+	/* hitting this means that DeviceTree left this gpio unspecified
+	 * by purpose but driver didn't take any measure to define its
+	 * behavior (i.e. aborting probe phase or disabling the feature).
+	 * driver needs to call of_is_valid_mmc_crg() for each expected
+	 * gpio to detect this case.
+	 */
+	if (WARN_ON(crg->gpios[gpio_num] < 0))
+		return -1;
+
+	value = gpio_get_value(crg->gpios[gpio_num]);
+	active_low = crg->alow_gpios[gpio_num];
+	return value ^ active_low;
+}
+
+int of_get_mmc_cd_gpio(struct of_mmc_crg *crg)
+{
+	return of_read_mmc_gpio(crg, CD_MMC_GPIO);
+}
+EXPORT_SYMBOL(of_get_mmc_cd_gpio);
+
+int of_get_mmc_ro_gpio(struct of_mmc_crg *crg)
+{
+	return of_read_mmc_gpio(crg, WP_MMC_GPIO);
+}
+EXPORT_SYMBOL(of_get_mmc_ro_gpio);
+
+int of_is_valid_mmc_crg(struct of_mmc_crg *crg, int gpio_num)
+{
+	BUG_ON(gpio_num >= NUM_MMC_GPIOS);
+	return gpio_is_valid(crg->gpios[gpio_num]);
+}
+EXPORT_SYMBOL(of_is_valid_mmc_crg);
+
+int of_get_mmc_crg(struct device *dev, struct device_node *np,
+                   int cd_off, struct of_mmc_crg *crg)
+{
+	int *gpio, *alow;
+	int i, ret;
+
+	memset(crg, 0, sizeof(*crg));
+	crg->cd_irq = -1;
+
+	gpio = crg->gpios;
+	alow = crg->alow_gpios;
+	for (i = 0; i < NUM_MMC_GPIOS; i++, gpio++, alow++) {
+		enum of_gpio_flags gpio_flags;
+		*gpio = of_get_gpio_flags(np, cd_off+i, &gpio_flags);
+		*alow = !!(gpio_flags & OF_GPIO_ACTIVE_LOW);
+
+		if (*gpio == -EEXIST || *gpio == -ENOENT) {
+			/* driver needs to define proper meaning of this missing
+			   gpio (i.e. abort probe or disable the feature) */
+			pr_debug("%s: gpio #%d is not specified\n", __func__, i);
+			continue;
+		}
+		if (*gpio < 0) {
+			pr_debug("%s: invalid configuration\n", __func__);
+			ret = *gpio;
+			break;
+		}
+		if (!gpio_is_valid(*gpio)) {
+			pr_debug("%s: gpio #%d is not valid: %d\n", __func__, i, *gpio);
+			ret = -EINVAL;
+			break;
+		}
+		ret = gpio_request(*gpio, dev_name(dev));
+		if (ret < 0) {
+			pr_debug("%s: gpio #%d is not available: %d\n", __func__, i, *gpio);
+			break;
+		}
+	}
+
+	if (i < NUM_MMC_GPIOS) {
+		while (--gpio >= crg->gpios)
+			if (gpio_is_valid(*gpio))
+				gpio_free(*gpio);
+		return ret;
+	}
+
+	if (gpio_is_valid(crg->gpios[CD_MMC_GPIO])) {
+		gpio_direction_input(crg->gpios[CD_MMC_GPIO]);
+		crg->cd_irq = gpio_to_irq(crg->gpios[CD_MMC_GPIO]);
+		if (crg->cd_irq < 0)
+			pr_debug("%s: cannot get cd irq number\n", __func__);
+	}
+	if (gpio_is_valid(crg->gpios[WP_MMC_GPIO]))
+		gpio_direction_input(crg->gpios[WP_MMC_GPIO]);
+
+	return 0;
+}
+EXPORT_SYMBOL(of_get_mmc_crg);
+
+void of_put_mmc_crg(struct of_mmc_crg *crg)
+{
+	int i;
+	for (i = 0; i < NUM_MMC_GPIOS; i++)
+		if (gpio_is_valid(crg->gpios[i]))
+			gpio_free(crg->gpios[i]);
+}
+EXPORT_SYMBOL(of_put_mmc_crg);
+
+u32 of_get_mmc_ocr_mask(struct device_node *np)
+{
+	const u32 *voltage_ranges;
+	int num_ranges;
+	u32 ocr_mask;
+	int i, j;
+
+	voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
+	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
+	if (!voltage_ranges || !num_ranges) {
+		pr_debug("%s: voltage-ranges unspecified\n", __func__);
+		return 0;
+	}
+
+	ocr_mask = 0;
+	for (i = 0, j = 0; i < num_ranges; i++) {
+		int vdd_min = be32_to_cpup(voltage_ranges++);
+		int vdd_max = be32_to_cpup(voltage_ranges++);
+		u32 mask = mmc_vddrange_to_ocrmask(vdd_min, vdd_max);
+
+		if (!mask) {
+			pr_debug("%s: voltage-range #%d is invalid\n", __func__, i);
+			return 0;
+		}
+		ocr_mask |= mask;
+	}
+
+	return ocr_mask;
+}
+EXPORT_SYMBOL(of_get_mmc_ocr_mask);
+
+MODULE_AUTHOR("Domenico Andreoli <cavok@gmail.com>");
+MODULE_LICENSE("GPL");
Index: b/include/linux/of_mmc.h
===================================================================
--- /dev/null
+++ b/include/linux/of_mmc.h
@@ -0,0 +1,50 @@ 
+/*
+ * OF helpers for the MMC API
+ *
+ * Copyright (c) 2011 Domenico Andreoli
+ *
+ * Heavily inspired by the OF support to the MMC-over-SPI driver made
+ * by Anton Vorontsov
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __LINUX_OF_MMC_H
+#define __LINUX_OF_MMC_H
+
+#include <linux/of.h>
+#include <linux/gpio.h>
+
+#ifdef CONFIG_OF_MMC
+
+enum {
+	CD_MMC_GPIO = 0,
+	WP_MMC_GPIO,
+	NUM_MMC_GPIOS,
+};
+
+/* Card detect and Read only Gpio data */
+struct of_mmc_crg {
+	int gpios[NUM_MMC_GPIOS];
+	int alow_gpios[NUM_MMC_GPIOS];
+	int cd_irq;
+};
+
+extern u32 of_get_mmc_ocr_mask(struct device_node *);
+extern int of_get_mmc_crg(struct device *, struct device_node *,
+                          int cd_off, struct of_mmc_crg *);
+
+/* if board does not use cd interrupts, driver can optimize polling
+   using this function. */
+extern int of_get_mmc_cd_gpio(struct of_mmc_crg *);
+/* sense switch on sd cards */
+extern int of_get_mmc_ro_gpio(struct of_mmc_crg *);
+extern int of_is_valid_mmc_crg(struct of_mmc_crg *, int gpio_num);
+extern void of_put_mmc_crg(struct of_mmc_crg *);
+
+#endif /* CONFIG_OF_MMC */
+
+#endif /* __LINUX_OF_MMC_H */