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