1a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm/*
2a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * SuperH Mobile SDHI
3a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
4a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Copyright (C) 2009 Magnus Damm
5a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
6a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * This program is free software; you can redistribute it and/or modify
7a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * it under the terms of the GNU General Public License version 2 as
8a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * published by the Free Software Foundation.
9a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
10a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Based on "Compaq ASIC3 support":
11a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
12a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Copyright 2001 Compaq Computer Corporation.
13a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Copyright 2004-2005 Phil Blundell
14a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Copyright 2007-2008 OpenedHand Ltd.
15a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
16a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm * Authors: Phil Blundell <pb@handhelds.org>,
17a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *	    Samuel Ortiz <sameo@openedhand.com>
18a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm *
19a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm */
20a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
21a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm#include <linux/kernel.h>
22a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm#include <linux/clk.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2488b47679746b81534002bcba42da97ab82b5d12aPaul Gortmaker#include <linux/module.h>
25a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm#include <linux/platform_device.h>
263c49e810507c9d0659b8aa61f7f91aecda428ee3Magnus Damm#include <linux/mmc/host.h>
2742051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski#include <linux/mmc/sh_mobile_sdhi.h>
28a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm#include <linux/mfd/tmio.h>
29056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski#include <linux/sh_dma.h>
30973ed3af1a570612771ed10dec6506c757767668Simon Horman#include <linux/delay.h>
31a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
3242051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski#include "tmio_mmc.h"
3342051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski
34a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Dammstruct sh_mobile_sdhi {
35a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	struct clk *clk;
36a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	struct tmio_mmc_data mmc_data;
37056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	struct sh_dmae_slave param_tx;
38056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	struct sh_dmae_slave param_rx;
39056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	struct tmio_mmc_dma dma_priv;
40a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm};
41a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
4242051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetskistatic void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
43be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm{
44be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
45be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm
46be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm	if (p && p->set_pwr)
47be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm		p->set_pwr(pdev, state);
48be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm}
49be9cd7b6f84fd0cc59c8770771073b5c66f958acMagnus Damm
5042051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetskistatic int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
51998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann{
52998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
53998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann
54998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann	if (p && p->get_cd)
55998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann		return p->get_cd(pdev);
56998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann	else
57998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann		return -ENOSYS;
58998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann}
59998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann
60973ed3af1a570612771ed10dec6506c757767668Simon Hormanstatic int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
61973ed3af1a570612771ed10dec6506c757767668Simon Horman{
62973ed3af1a570612771ed10dec6506c757767668Simon Horman	int timeout = 1000;
63973ed3af1a570612771ed10dec6506c757767668Simon Horman
64973ed3af1a570612771ed10dec6506c757767668Simon Horman	while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13)))
65973ed3af1a570612771ed10dec6506c757767668Simon Horman		udelay(1);
66973ed3af1a570612771ed10dec6506c757767668Simon Horman
67973ed3af1a570612771ed10dec6506c757767668Simon Horman	if (!timeout) {
68973ed3af1a570612771ed10dec6506c757767668Simon Horman		dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n");
69973ed3af1a570612771ed10dec6506c757767668Simon Horman		return -EBUSY;
70973ed3af1a570612771ed10dec6506c757767668Simon Horman	}
71973ed3af1a570612771ed10dec6506c757767668Simon Horman
72973ed3af1a570612771ed10dec6506c757767668Simon Horman	return 0;
73973ed3af1a570612771ed10dec6506c757767668Simon Horman}
74973ed3af1a570612771ed10dec6506c757767668Simon Horman
75973ed3af1a570612771ed10dec6506c757767668Simon Hormanstatic int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
76973ed3af1a570612771ed10dec6506c757767668Simon Horman{
77973ed3af1a570612771ed10dec6506c757767668Simon Horman	switch (addr)
78973ed3af1a570612771ed10dec6506c757767668Simon Horman	{
79973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_SD_CMD:
80973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_STOP_INTERNAL_ACTION:
81973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_XFER_BLK_COUNT:
82973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_SD_CARD_CLK_CTL:
83973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_SD_XFER_LEN:
84973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_SD_MEM_CARD_OPT:
85973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_TRANSACTION_CTL:
86973ed3af1a570612771ed10dec6506c757767668Simon Horman	case CTL_DMA_ENABLE:
87973ed3af1a570612771ed10dec6506c757767668Simon Horman		return sh_mobile_sdhi_wait_idle(host);
88973ed3af1a570612771ed10dec6506c757767668Simon Horman	}
89973ed3af1a570612771ed10dec6506c757767668Simon Horman
90973ed3af1a570612771ed10dec6506c757767668Simon Horman	return 0;
91973ed3af1a570612771ed10dec6506c757767668Simon Horman}
92973ed3af1a570612771ed10dec6506c757767668Simon Horman
937f524217439cc17da74523582c303cced432713eGuennadi Liakhovetskistatic void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
947f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski{
957f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski	mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
967f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski}
977f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski
987f524217439cc17da74523582c303cced432713eGuennadi Liakhovetskistatic const struct sh_mobile_sdhi_ops sdhi_ops = {
997f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski	.cd_wakeup = sh_mobile_sdhi_cd_wakeup,
1007f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski};
1017f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski
10225ab998e2eff46d2e6ede80c9fc02a349fa005a3Paul Mundtstatic int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
103a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm{
104a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	struct sh_mobile_sdhi *priv;
105056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	struct tmio_mmc_data *mmc_data;
106056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
10742051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	struct tmio_mmc_host *host;
108a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	char clk_name[8];
109d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	int irq, ret, i = 0;
110d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	bool multiplexed_isr = true;
111a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
112a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
113a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	if (priv == NULL) {
114a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		dev_err(&pdev->dev, "kzalloc failed\n");
115a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		return -ENOMEM;
116a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	}
117a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
118056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	mmc_data = &priv->mmc_data;
1192595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski	p->pdata = mmc_data;
120056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski
121e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht	if (p->init) {
1227f524217439cc17da74523582c303cced432713eGuennadi Liakhovetski		ret = p->init(pdev, &sdhi_ops);
123e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht		if (ret)
124e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht			goto einit;
125e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht	}
126e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht
127a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
128a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	priv->clk = clk_get(&pdev->dev, clk_name);
129a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	if (IS_ERR(priv->clk)) {
130a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
131a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		ret = PTR_ERR(priv->clk);
13242051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski		goto eclkget;
133a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	}
134a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
135056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	mmc_data->hclk = clk_get_rate(priv->clk);
136056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
137998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann	mmc_data->get_cd = sh_mobile_sdhi_get_cd;
138056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski	mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
139bb0fe533514c1d480c6c16f8bad070270a73a96cGuennadi Liakhovetski	if (p) {
140f87c20a9db43f6f731270eeef616e1bcc266c2d4Guennadi Liakhovetski		mmc_data->flags = p->tmio_flags;
141b91df1593e361109f1fe665ce17c5e87ca60582bSimon Horman		if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
142b91df1593e361109f1fe665ce17c5e87ca60582bSimon Horman			mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
143bb0fe533514c1d480c6c16f8bad070270a73a96cGuennadi Liakhovetski		mmc_data->ocr_mask = p->tmio_ocr_mask;
144998283e2e359249133f2f47db26669a55ff25c98Arnd Hannemann		mmc_data->capabilities |= p->tmio_caps;
14558126c878b4a4f658015e383614bafb6331e46d3Guennadi Liakhovetski		mmc_data->cd_gpio = p->cd_gpio;
14642051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski
1473e713373ce07b9f59c3901e7d39bc1edccda28daGuennadi Liakhovetski		if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
14842051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			priv->param_tx.slave_id = p->dma_slave_tx;
14942051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			priv->param_rx.slave_id = p->dma_slave_rx;
15042051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			priv->dma_priv.chan_priv_tx = &priv->param_tx;
15142051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			priv->dma_priv.chan_priv_rx = &priv->param_rx;
15242051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
15342051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski			mmc_data->dma = &priv->dma_priv;
15442051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski		}
155bb0fe533514c1d480c6c16f8bad070270a73a96cGuennadi Liakhovetski	}
156056676dabd9f4c69a6adcad208e9aa2ca7241400Guennadi Liakhovetski
157f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda	/*
158f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda	 * All SDHI blocks support 2-byte and larger block sizes in 4-bit
159f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda	 * bus width mode.
160f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda	 */
161f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda	mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
162f1334fb3c3006ba109886158c0ad79512f928bc1Yusuke Goda
16323b66071e8ce7f359a0e410a8a3514bd3179e92eArnd Hannemann	/*
16423b66071e8ce7f359a0e410a8a3514bd3179e92eArnd Hannemann	 * All SDHI blocks support SDIO IRQ signalling.
16523b66071e8ce7f359a0e410a8a3514bd3179e92eArnd Hannemann	 */
16623b66071e8ce7f359a0e410a8a3514bd3179e92eArnd Hannemann	mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
16723b66071e8ce7f359a0e410a8a3514bd3179e92eArnd Hannemann
16842051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
16942051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	if (ret < 0)
17042051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski		goto eprobe;
171a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
172d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	/*
173d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	 * Allow one or more specific (named) ISRs or
174d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	 * one or more multiplexed (un-named) ISRs.
175d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	 */
176d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
177d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
178d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (irq >= 0) {
179d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		multiplexed_isr = false;
180d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		ret = request_irq(irq, tmio_mmc_card_detect_irq, 0,
181d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman				  dev_name(&pdev->dev), host);
182d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		if (ret)
183d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			goto eirq_card_detect;
184d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	}
185d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
186d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
187d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (irq >= 0) {
188d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		multiplexed_isr = false;
189d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		ret = request_irq(irq, tmio_mmc_sdio_irq, 0,
190d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman				  dev_name(&pdev->dev), host);
191d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		if (ret)
192d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			goto eirq_sdio;
193d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	}
194d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
195d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD);
196d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (irq >= 0) {
197d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		multiplexed_isr = false;
198d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		ret = request_irq(irq, tmio_mmc_sdcard_irq, 0,
199d6a1f863433bdf3f8406dedfa33fa79ee9259db3Magnus Damm				  dev_name(&pdev->dev), host);
200d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		if (ret)
201d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			goto eirq_sdcard;
202d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	} else if (!multiplexed_isr) {
203d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		dev_err(&pdev->dev,
204d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			"Principal SD-card IRQ is missing among named interrupts\n");
205d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		ret = irq;
206d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		goto eirq_sdcard;
207d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	}
208d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
209d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (multiplexed_isr) {
210d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		while (1) {
211d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			irq = platform_get_irq(pdev, i);
212d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			if (irq < 0)
213d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman				break;
214d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			i++;
215d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			ret = request_irq(irq, tmio_mmc_irq, 0,
216d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman					  dev_name(&pdev->dev), host);
217d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			if (ret)
218d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman				goto eirq_multiplexed;
219d6a1f863433bdf3f8406dedfa33fa79ee9259db3Magnus Damm		}
220d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
221d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		/* There must be at least one IRQ source */
222d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		if (!i)
223d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			goto eirq_multiplexed;
2248e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	}
225d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman
2261f7d6819e56dda651a32b0193ff9e7929f62709fMagnus Damm	dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
2271f7d6819e56dda651a32b0193ff9e7929f62709fMagnus Damm		 mmc_hostname(host->mmc), (unsigned long)
22858126c878b4a4f658015e383614bafb6331e46d3Guennadi Liakhovetski		 (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
2291f7d6819e56dda651a32b0193ff9e7929f62709fMagnus Damm		 mmc_data->hclk / 1000000);
230a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
23142051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	return ret;
232a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
233d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Hormaneirq_multiplexed:
234d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	while (i--) {
235d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		irq = platform_get_irq(pdev, i);
236d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		free_irq(irq, host);
237d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	}
238d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Hormaneirq_sdcard:
239d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
240d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (irq >= 0)
241d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		free_irq(irq, host);
242d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Hormaneirq_sdio:
243d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
244d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	if (irq >= 0)
245d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		free_irq(irq, host);
246d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Hormaneirq_card_detect:
2478e7bfdb37ac001c95d2c768932b57de1019409cdMagnus Damm	tmio_mmc_host_remove(host);
24842051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetskieprobe:
24942051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	clk_put(priv->clk);
25042051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetskieclkget:
251e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht	if (p->cleanup)
252e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht		p->cleanup(pdev);
253e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hechteinit:
25442051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	kfree(priv);
255a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	return ret;
256a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm}
257a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
258a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Dammstatic int sh_mobile_sdhi_remove(struct platform_device *pdev)
259a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm{
26042051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	struct mmc_host *mmc = platform_get_drvdata(pdev);
26142051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	struct tmio_mmc_host *host = mmc_priv(mmc);
26242051e8a7bce76ebd3cd201704ee2427120636e1Guennadi Liakhovetski	struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
2632595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
264d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	int i = 0, irq;
265d6a1f863433bdf3f8406dedfa33fa79ee9259db3Magnus Damm
2662595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski	p->pdata = NULL;
2672595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski
268742a0c7cae9bd0f913c71722289b8ec862d70a2bGuennadi Liakhovetski	tmio_mmc_host_remove(host);
269742a0c7cae9bd0f913c71722289b8ec862d70a2bGuennadi Liakhovetski
270d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman	while (1) {
271d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		irq = platform_get_irq(pdev, i++);
272d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		if (irq < 0)
273d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman			break;
274d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28Simon Horman		free_irq(irq, host);
275d6a1f863433bdf3f8406dedfa33fa79ee9259db3Magnus Damm	}
276a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
277a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	clk_put(priv->clk);
278e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht
279e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht	if (p->cleanup)
280e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht		p->cleanup(pdev);
281e82b4ac94e5c43fad51b975aed058858ceda1f0fBastian Hecht
282a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	kfree(priv);
283a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
284a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	return 0;
285a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm}
286a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
287e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetskistatic const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
288e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski	.suspend = tmio_mmc_host_suspend,
289e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski	.resume = tmio_mmc_host_resume,
2902595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski	.runtime_suspend = tmio_mmc_host_runtime_suspend,
2912595880481ac894d390365092de9aaf92b44e147Guennadi Liakhovetski	.runtime_resume = tmio_mmc_host_runtime_resume,
292e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski};
293e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski
294a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Dammstatic struct platform_driver sh_mobile_sdhi_driver = {
295a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	.driver		= {
296a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		.name	= "sh_mobile_sdhi",
297a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm		.owner	= THIS_MODULE,
298e6ee7182c3b22afe0b983eac89dc020a93a13179Guennadi Liakhovetski		.pm	= &tmio_mmc_dev_pm_ops,
299a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	},
300a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	.probe		= sh_mobile_sdhi_probe,
301a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm	.remove		= __devexit_p(sh_mobile_sdhi_remove),
302a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm};
303a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
304d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(sh_mobile_sdhi_driver);
305a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus Damm
306a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus DammMODULE_DESCRIPTION("SuperH Mobile SDHI driver");
307a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus DammMODULE_AUTHOR("Magnus Damm");
308a87d563873a6f1ee98233b57af665f2d0fc90ebbMagnus DammMODULE_LICENSE("GPL v2");
30942051e8a7bce76ebd3cd201704ee2427120636e1Guennadi LiakhovetskiMODULE_ALIAS("platform:sh_mobile_sdhi");
310