summaryrefslogtreecommitdiffstats
path: root/0002-omap_hsmmc-Add-reset-gpio.patch
blob: ea686e78e8b398e33efd5be6fdf62e91ab196b8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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