On Thu, Apr 21, 2011 at 03:19:57PM +0200, Domenico Andreoli wrote:
> From: Domenico Andreoli
>
> 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
> ---
> 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
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +
> +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_