@@ -102,6 +102,7 @@ static struct omap2_hsmmc_info mmc[] = {
* but is a phoenix interrupt
*/
.gpio_cd = TWL6030_IRQ_BASE + MMCDETECT_INTR_OFFSET,
+ .cd_type = true,
.gpio_wp = -EINVAL,
},
{
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/i2c/twl.h>
#include <mach/hardware.h>
#include <plat/control.h>
#include <plat/mmc.h>
@@ -189,6 +190,7 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info
mmc->get_context_loss_count = hsmmc_get_context_loss;
mmc->slots[0].switch_pin = c->gpio_cd;
+ mmc->slots[0].nongpio_cd = c->cd_type;
mmc->slots[0].gpio_wp = c->gpio_wp;
mmc->slots[0].remux = c->remux;
@@ -17,6 +17,7 @@ struct omap2_hsmmc_info {
bool no_off; /* power_saving and power is not to go off */
bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
int gpio_cd; /* or -EINVAL */
+ bool cd_type; /* Card detect Type:NON-GPIO=true,GPIO=flase */
int gpio_wp; /* or -EINVAL */
char *name; /* or NULL for default */
struct device *dev; /* returned: pointer to mmc adapter */
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/mmc/host.h>
+#include <linux/i2c/twl.h>
#include <plat/board.h>
@@ -103,6 +104,7 @@ struct omap_mmc_platform_data {
unsigned vcc_aux_disable_is_sleep:1;
int switch_pin; /* gpio (card detect) */
+ unsigned nongpio_cd:1; /* NON-GPIO=true , GPIO=false */
int gpio_wp; /* gpio (write protect) */
int (*set_bus_mode)(struct device *dev, int slot, int bus_mode);
@@ -36,6 +36,7 @@
#include <linux/irq.h>
#include <linux/kthread.h>
#include <linux/i2c/twl.h>
+#include <linux/platform_device.h>
/*
* TWL6030 (unlike its predecessors, which had two level interrupt handling)
@@ -223,6 +224,32 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset)
}
EXPORT_SYMBOL(twl6030_interrupt_mask);
+int twl6030_mmc_card_detect(struct device *dev, int slot)
+{
+ int ret = -ENOSYS;
+ int res = 0;
+ u8 read_reg;
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+
+ switch (pdev->id) {
+ case 0:
+ /*
+ * BIT0 of REG_MMC_CTRL
+ * 0 - Card not present ,1 - Card present
+ */
+ res = twl_i2c_read_u8(TWL6030_MODULE_ID0,
+ &read_reg, TWL6030_MMCCTRL);
+ if (res >= 0)
+ ret = read_reg & 0x1;
+ break;
+ default:
+ pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(twl6030_mmc_card_detect);
+
int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
{
@@ -505,6 +505,18 @@ err_free_sp:
return ret;
}
+static int omap_hsmmc_non_gpio_init(struct omap_mmc_platform_data *pdata)
+{
+ if (pdata->slots[0].switch_pin) {
+ pdata->suspend = omap_hsmmc_suspend_cdirq;
+ pdata->resume = omap_hsmmc_resume_cdirq;
+ pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+ pdata->slots[0].card_detect_irq = pdata->slots[0].switch_pin;
+ return 0;
+ }
+ return -1;
+}
+
static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
{
if (gpio_is_valid(pdata->slots[0].gpio_wp))
@@ -1977,7 +1989,11 @@ static int __init omap_hsmmc_probe(struct platform_device
if (res == NULL)
return -EBUSY;
- ret = omap_hsmmc_gpio_init(pdata);
+ if (!pdata->slots[0].nongpio_cd)
+ ret = omap_hsmmc_gpio_init(pdata);
+ else
+ ret = omap_hsmmc_non_gpio_init(pdata);
+
if (ret)
goto err;
@@ -141,6 +141,7 @@
#define TWL6030_CHARGER_CTRL_INT_MASK 0x10
#define TWL6030_CHARGER_FAULT_INT_MASK 0x60
+#define TWL6030_MMCCTRL 0xEE
#define TWL4030_CLASS_ID 0x4030
#define TWL6030_CLASS_ID 0x6030
@@ -173,6 +174,11 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
+/*
+ * MMC1 Controller on OMAP4 uses Phoenix Irq for Card detect.
+ */
+int twl6030_mmc_card_detect(struct device *dev, int slot);
+
/*----------------------------------------------------------------------*/
/*