* Anuj Aggarwal <anuj.aggarwal@xxxxxx> [091123 10:24]: > Add init code for HSMMC controller for AM3517 platform. This seems like a copy of the older mmc-twl4030.c? Can you please specify what is different compared to mmc-twl4030.c? I'd rather not have all this code duplicated, it's going to be a pain to maintain. I guess with the regulator framework most of this code should be generic. Regards, Tony > Signed-off-by: Anuj Aggarwal <anuj.aggarwal@xxxxxx> > --- > arch/arm/mach-omap2/mmc-am3517evm.c | 267 +++++++++++++++++++++++++++++++++++ > arch/arm/mach-omap2/mmc-am3517evm.h | 22 +++ > 2 files changed, 289 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/mach-omap2/mmc-am3517evm.c > create mode 100644 arch/arm/mach-omap2/mmc-am3517evm.h > > diff --git a/arch/arm/mach-omap2/mmc-am3517evm.c b/arch/arm/mach-omap2/mmc-am3517evm.c > new file mode 100644 > index 0000000..7995239 > --- /dev/null > +++ b/arch/arm/mach-omap2/mmc-am3517evm.c > @@ -0,0 +1,267 @@ > +/* > + * linux/arch/arm/mach-omap2/mmc-am3517evm.c > + * > + * Copyright (C) 2009 Texas Instruments Incorporated > + * Author: Anuj Aggarwal <anuj.aggarwal@xxxxxx> > + * > + * Based on mach-omap2/mmc-twl4030.c > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/interrupt.h> > +#include <linux/delay.h> > +#include <linux/gpio.h> > + > +#include <mach/hardware.h> > +#include <plat/control.h> > +#include <plat/mmc.h> > +#include <plat/board.h> > +#include "mmc-am3517evm.h" > + > +#define LDO_CLR 0x00 > +#define VSEL_S2_CLR 0x40 > + > +#define VMMC1_DEV_GRP 0x27 > +#define VMMC1_CLR 0x00 > +#define VMMC1_315V 0x03 > +#define VMMC1_300V 0x02 > +#define VMMC1_285V 0x01 > +#define VMMC1_185V 0x00 > +#define VMMC1_DEDICATED 0x2A > + > +#define VMMC2_DEV_GRP 0x2B > +#define VMMC2_CLR 0x40 > +#define VMMC2_315V 0x0c > +#define VMMC2_300V 0x0b > +#define VMMC2_285V 0x0a > +#define VMMC2_260V 0x08 > +#define VMMC2_185V 0x06 > +#define VMMC2_DEDICATED 0x2E > + > +#define VMMC_DEV_GRP_P1 0x20 > + > +#define HSMMC_NAME_LEN 9 > + > +#if defined(CONFIG_REGULATOR) || \ > + (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ > + defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) > + > +/* > + * MMC definitions > + * > + */ > +static struct mmc_controller { > + struct omap_mmc_platform_data *mmc; > + u8 vmmc_dev_grp; > + u8 vmmc_dedicated; > + char name[HSMMC_NAME_LEN]; > +} hsmmc[] = { > + { > + .vmmc_dev_grp = VMMC1_DEV_GRP, > + .vmmc_dedicated = VMMC1_DEDICATED, > + }, > + { > + .vmmc_dev_grp = VMMC2_DEV_GRP, > + .vmmc_dedicated = VMMC2_DEDICATED, > + }, > +}; > + > +static int mmc_card_detect(int irq) > +{ > + unsigned i; > + > + for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { > + struct omap_mmc_platform_data *mmc; > + > + mmc = hsmmc[i].mmc; > + if (!mmc) > + continue; > + if (irq != mmc->slots[0].card_detect_irq) > + continue; > + > + /* NOTE: assumes card detect signal is active-low */ > + return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); > + } > + return -ENOSYS; > +} > + > +static int mmc_get_ro(struct device *dev, int slot) > +{ > + struct omap_mmc_platform_data *mmc = dev->platform_data; > + > + /* NOTE: assumes write protect signal is active-high */ > + return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); > +} > + > +/* > + * MMC Slot Initialization. > + */ > +static int mmc_late_init(struct device *dev) > +{ > + struct omap_mmc_platform_data *mmc = dev->platform_data; > + int ret = 0; > + int i; > + > + ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); > + if (ret) > + goto done; > + ret = gpio_direction_input(mmc->slots[0].switch_pin); > + if (ret) > + goto err; > + > + for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { > + if (hsmmc[i].name == mmc->slots[0].name) { > + hsmmc[i].mmc = mmc; > + break; > + } > + } > + > + return 0; > + > +err: > + gpio_free(mmc->slots[0].switch_pin); > +done: > + mmc->slots[0].card_detect_irq = 0; > + mmc->slots[0].card_detect = NULL; > + > + dev_err(dev, "err %d configuring card detect\n", ret); > + return ret; > +} > + > +static void mmc_cleanup(struct device *dev) > +{ > + struct omap_mmc_platform_data *mmc = dev->platform_data; > + > + gpio_free(mmc->slots[0].switch_pin); > +} > + > +#ifdef CONFIG_PM > + > +static int mmc_suspend(struct device *dev, int slot) > +{ > + struct omap_mmc_platform_data *mmc = dev->platform_data; > + > + disable_irq(mmc->slots[0].card_detect_irq); > + return 0; > +} > + > +static int mmc_resume(struct device *dev, int slot) > +{ > + struct omap_mmc_platform_data *mmc = dev->platform_data; > + > + enable_irq(mmc->slots[0].card_detect_irq); > + return 0; > +} > + > +#else > +#define mmc_suspend NULL > +#define mmc_resume NULL > +#endif > + > +/* > + * the MMC power setting function > + */ > + > +static int mmc1_set_power(struct device *dev, int slot, int power_on, > + int vdd) > +{ > + return 0; > +} > + > +static int mmc2_set_power(struct device *dev, int slot, int power_on, int vdd) > +{ > + return 0; > +} > + > +static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; > + > +void __init am3517_mmc_init(struct am3517_hsmmc_info *controllers) > +{ > + struct am3517_hsmmc_info *c; > + int nr_hsmmc = ARRAY_SIZE(hsmmc_data); > + > + for (c = controllers; c->mmc; c++) { > + struct mmc_controller *mmc_control = hsmmc + c->mmc - 1; > + struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; > + > + if (!c->mmc || c->mmc > nr_hsmmc) { > + pr_debug("MMC%d: no such controller\n", c->mmc); > + continue; > + } > + if (mmc) { > + pr_debug("MMC%d: already configured\n", c->mmc); > + continue; > + } > + > + mmc = kzalloc(sizeof(struct omap_mmc_platform_data), > + GFP_KERNEL); > + if (!mmc) { > + pr_err("Cannot allocate memory for mmc device!\n"); > + return; > + } > + > + sprintf(mmc_control->name, "mmc%islot%i", c->mmc, 1); > + mmc->slots[0].name = mmc_control->name; > + mmc->nr_slots = 1; > + mmc->slots[0].ocr_mask = MMC_VDD_165_195 | > + MMC_VDD_26_27 | MMC_VDD_27_28 | > + MMC_VDD_29_30 | > + MMC_VDD_30_31 | MMC_VDD_31_32; > + mmc->slots[0].wires = c->wires; > + mmc->slots[0].internal_clock = !c->ext_clock; > + mmc->dma_mask = 0xffffffff; > + > + if (1) { > + mmc->init = mmc_late_init; > + mmc->cleanup = mmc_cleanup; > + mmc->suspend = mmc_suspend; > + mmc->resume = mmc_resume; > + > + mmc->slots[0].switch_pin = c->gpio_cd; > + mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd); > + mmc->slots[0].card_detect = mmc_card_detect; > + } else > + mmc->slots[0].switch_pin = -EINVAL; > + > + /* write protect normally uses an OMAP gpio */ > + if (gpio_is_valid(c->gpio_wp)) { > + gpio_request(c->gpio_wp, "mmc_wp"); > + gpio_direction_input(c->gpio_wp); > + > + mmc->slots[0].gpio_wp = c->gpio_wp; > + mmc->slots[0].get_ro = mmc_get_ro; > + } else > + mmc->slots[0].gpio_wp = -EINVAL; > + > + /* NOTE: we assume OMAP's MMC1 and MMC2 use > + * the TWL4030's VMMC1 and VMMC2, respectively; > + * and that OMAP's MMC3 isn't used. > + */ > + > + switch (c->mmc) { > + case 1: > + mmc->slots[0].set_power = mmc1_set_power; > + break; > + case 2: > + mmc->slots[0].set_power = mmc2_set_power; > + break; > + default: > + pr_err("MMC%d configuration not supported!\n", c->mmc); > + continue; > + } > + hsmmc_data[c->mmc - 1] = mmc; > + } > + > + omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC); > +} > +#else > +inline void am3517_mmc_init(struct am3517_hsmmc_info *info) > +{ > +} > +#endif > diff --git a/arch/arm/mach-omap2/mmc-am3517evm.h b/arch/arm/mach-omap2/mmc-am3517evm.h > new file mode 100644 > index 0000000..bf2d339 > --- /dev/null > +++ b/arch/arm/mach-omap2/mmc-am3517evm.h > @@ -0,0 +1,22 @@ > +/* > + * MMC definitions for OMAP3517 / AM3517 > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +struct am3517_hsmmc_info { > + u8 mmc; /* controller 1/2/3 */ > + u8 wires; /* 1/4/8 wires */ > + bool transceiver; /* MMC-2 option */ > + bool ext_clock; /* use external pin for input clock */ > + bool cover_only; /* No card detect - just cover switch */ > + int gpio_cd; /* or -EINVAL */ > + int gpio_wp; /* or -EINVAL */ > + char *name; /* or NULL for default */ > + struct device *dev; /* returned: pointer to mmc adapter */ > + int ocr_mask; /* temporary HACK */ > +}; > + > +void am3517_mmc_init(struct am3517_hsmmc_info *); > -- > 1.6.2.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html