139 lines
4.8 KiB
Diff
139 lines
4.8 KiB
Diff
From 364d4535955f21a8ce13e969aedde946a2d566b8 Mon Sep 17 00:00:00 2001
|
|
From: Pantelis Antoniou <panto@antoniou-consulting.com>
|
|
Date: Fri, 30 Nov 2012 12:18:16 +0200
|
|
Subject: [PATCH 2/2] omap_hsmmc: Add reset gpio
|
|
|
|
Add a gpio property for controlling reset of the mmc device.
|
|
eMMC on the beaglebone black requires it.
|
|
|
|
Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
|
|
---
|
|
drivers/mmc/host/omap_hsmmc.c | 40 +++++++++++++++++++++++++++++++++-
|
|
include/linux/platform_data/mmc-omap.h | 3 +++
|
|
2 files changed, 42 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
|
|
index 8ab4a93..1fe7469 100644
|
|
--- a/drivers/mmc/host/omap_hsmmc.c
|
|
+++ b/drivers/mmc/host/omap_hsmmc.c
|
|
@@ -40,6 +40,8 @@
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/platform_data/mmc-omap.h>
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/err.h>
|
|
|
|
/* OMAP HSMMC Host Controller Registers */
|
|
#define OMAP_HSMMC_SYSSTATUS 0x0014
|
|
@@ -396,6 +398,7 @@ static inline int omap_hsmmc_have_reg(void)
|
|
static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
|
|
{
|
|
int ret;
|
|
+ unsigned long flags;
|
|
|
|
if (gpio_is_valid(pdata->slots[0].switch_pin)) {
|
|
if (pdata->slots[0].cover)
|
|
@@ -425,6 +428,24 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
|
|
} else
|
|
pdata->slots[0].gpio_wp = -EINVAL;
|
|
|
|
+ if (gpio_is_valid(pdata->slots[0].gpio_reset)) {
|
|
+ flags = pdata->slots[0].gpio_reset_active_low ?
|
|
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
|
|
+ ret = gpio_request_one(pdata->slots[0].gpio_reset, flags,
|
|
+ "mmc_reset");
|
|
+ if (ret)
|
|
+ goto err_free_wp;
|
|
+
|
|
+ /* hold reset */
|
|
+ udelay(pdata->slots[0].gpio_reset_hold_us);
|
|
+
|
|
+ gpio_set_value(pdata->slots[0].gpio_reset,
|
|
+ !pdata->slots[0].gpio_reset_active_low);
|
|
+
|
|
+ } else
|
|
+ pdata->slots[0].gpio_reset = -EINVAL;
|
|
+
|
|
+
|
|
return 0;
|
|
|
|
err_free_wp:
|
|
@@ -438,6 +459,8 @@ err_free_sp:
|
|
|
|
static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
|
|
{
|
|
+ if (gpio_is_valid(pdata->slots[0].gpio_reset))
|
|
+ gpio_free(pdata->slots[0].gpio_reset);
|
|
if (gpio_is_valid(pdata->slots[0].gpio_wp))
|
|
gpio_free(pdata->slots[0].gpio_wp);
|
|
if (gpio_is_valid(pdata->slots[0].switch_pin))
|
|
@@ -792,7 +815,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
|
|
* ac, bc, adtc, bcr. Only commands ending an open ended transfer need
|
|
* a val of 0x3, rest 0x0.
|
|
*/
|
|
- if (cmd == host->mrq->stop)
|
|
+ if (host->mrq && cmd == host->mrq->stop)
|
|
cmdtype = 0x3;
|
|
|
|
cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
|
|
@@ -835,6 +858,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
|
|
int completed;
|
|
unsigned long flags;
|
|
|
|
+ BUG_ON(mrq == NULL);
|
|
+
|
|
spin_lock_irqsave(&host->irq_lock, flags);
|
|
|
|
host->req_flags &= ~RQF_REQ_IN_PROGRESS;
|
|
@@ -1775,6 +1800,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
|
|
struct device_node *np = dev->of_node;
|
|
u32 bus_width, max_freq;
|
|
int cd_gpio, wp_gpio;
|
|
+ enum of_gpio_flags reset_flags;
|
|
|
|
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
|
|
wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
|
|
@@ -1792,6 +1818,14 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
|
|
pdata->nr_slots = 1;
|
|
pdata->slots[0].switch_pin = cd_gpio;
|
|
pdata->slots[0].gpio_wp = wp_gpio;
|
|
+ reset_flags = 0;
|
|
+ pdata->slots[0].gpio_reset = of_get_named_gpio_flags(np,
|
|
+ "reset-gpios", 0, &reset_flags);
|
|
+ pdata->slots[0].gpio_reset_active_low =
|
|
+ (reset_flags & OF_GPIO_ACTIVE_LOW) != 0;
|
|
+ pdata->slots[0].gpio_reset_hold_us = 100; /* default */
|
|
+ of_property_read_u32(np, "reset-gpio-hold-us",
|
|
+ &pdata->slots[0].gpio_reset_hold_us);
|
|
|
|
if (of_find_property(np, "ti,non-removable", NULL)) {
|
|
pdata->slots[0].nonremovable = true;
|
|
@@ -1858,6 +1892,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|
return -ENXIO;
|
|
}
|
|
|
|
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
|
+ if (IS_ERR(pinctrl))
|
|
+ dev_warn(&pdev->dev, "unable to select pin group\n");
|
|
+
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
irq = platform_get_irq(pdev, 0);
|
|
if (res == NULL || irq < 0)
|
|
diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h
|
|
index 2bf1b30..d548994 100644
|
|
--- a/include/linux/platform_data/mmc-omap.h
|
|
+++ b/include/linux/platform_data/mmc-omap.h
|
|
@@ -115,6 +115,9 @@ struct omap_mmc_platform_data {
|
|
|
|
int switch_pin; /* gpio (card detect) */
|
|
int gpio_wp; /* gpio (write protect) */
|
|
+ int gpio_reset; /* gpio (reset) */
|
|
+ int gpio_reset_active_low; /* 1 if reset is active low */
|
|
+ u32 gpio_reset_hold_us; /* time to hold in us */
|
|
|
|
int (*set_bus_mode)(struct device *dev, int slot, int bus_mode);
|
|
int (*set_power)(struct device *dev, int slot,
|
|
--
|
|
1.8.2.1
|
|
|