disable socket power in adapter driver instead of media one

Socket power must be fully controlled by adapter driver. This also prevents
unnecessary power-off of the socket when media driver is unloaded, yet
media remains in the socket.

Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 1ba6c08..c08ad8f 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -105,7 +105,8 @@
 	    == TIFM_TYPE_XD)
 		msleep(40);
 
-	writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+	writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00,
+	       sock_addr + SOCK_CONTROL);
 	/* wait for power to stabilize */
 	msleep(20);
 	for (cnt = 16; cnt <= 256; cnt <<= 1) {
@@ -122,6 +123,12 @@
 	return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
 }
 
+inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr)
+{
+	writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL),
+	       sock_addr + SOCK_CONTROL);
+}
+
 inline static char __iomem *
 tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
 {
@@ -133,6 +140,7 @@
 	struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
 					       media_switcher);
 	struct tifm_dev *sock;
+	char __iomem *sock_addr;
 	unsigned long flags;
 	unsigned char media_id;
 	unsigned int socket_change_set, cnt;
@@ -158,11 +166,12 @@
 			       "%s : demand removing card from socket %u:%u\n",
 			       fm->cdev.class_id, fm->id, cnt);
 			fm->sockets[cnt] = NULL;
+			sock_addr = sock->addr;
 			spin_unlock_irqrestore(&fm->lock, flags);
 			device_unregister(&sock->dev);
 			spin_lock_irqsave(&fm->lock, flags);
-			writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
-			       + SOCK_CONTROL);
+			tifm_7xx1_sock_power_off(sock_addr);
+			writel(0x0e00, sock_addr + SOCK_CONTROL);
 		}
 
 		spin_unlock_irqrestore(&fm->lock, flags);
@@ -205,8 +214,16 @@
 
 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
 {
+	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	int cnt;
+
 	dev_dbg(&dev->dev, "suspending host\n");
 
+	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+		if (fm->sockets[cnt])
+			tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr);
+	}
+
 	pci_save_state(dev);
 	pci_enable_wake(dev, pci_choose_state(dev, state), 0);
 	pci_disable_device(dev);
@@ -357,6 +374,7 @@
 static void tifm_7xx1_remove(struct pci_dev *dev)
 {
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	int cnt;
 
 	fm->eject = tifm_7xx1_dummy_eject;
 	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
@@ -365,6 +383,9 @@
 
 	tifm_remove_adapter(fm);
 
+	for (cnt = 0; cnt < fm->num_sockets; cnt++)
+		tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt));
+
 	pci_set_drvdata(dev, NULL);
 
 	iounmap(fm->addr);
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 7511f96..8b736e9 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -1021,10 +1021,6 @@
 	mmc_remove_host(mmc);
 	dev_dbg(&sock->dev, "after remove\n");
 
-	/* The meaning of the bit majority in this constant is unknown. */
-	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-
 	mmc_free_host(mmc);
 }
 
@@ -1032,14 +1028,7 @@
 
 static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	int rc;
-
-	rc = mmc_suspend_host(mmc, state);
-	/* The meaning of the bit majority in this constant is unknown. */
-	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-	return rc;
+	return mmc_suspend_host(tifm_get_drvdata(sock), state);
 }
 
 static int tifm_sd_resume(struct tifm_dev *sock)
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index 2a19698..6b3a318 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -63,6 +63,7 @@
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
+#define TIFM_CTRL_POWER_MASK      0x00000007
 
 #define TIFM_SOCK_STATE_OCCUPIED  0x00000008
 #define TIFM_SOCK_STATE_POWERED   0x00000080