1c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR/* 2c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * drivers/mmc/host/sdhci-spear.c 3c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * 4c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * Support of SDHCI platform devices for spear soc family 5c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * 6c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * Copyright (C) 2010 ST Microelectronics 7c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * Viresh Kumar<viresh.kumar@st.com> 8c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * 9c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * Inspired by sdhci-pltfm.c 10c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * 11c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * This file is licensed under the terms of the GNU General Public 12c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * License version 2. This program is licensed "as is" without any 13c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * warranty of any kind, whether express or implied. 14c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR */ 15c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 16c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/clk.h> 17c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/delay.h> 18c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/gpio.h> 19c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/highmem.h> 2088b47679746b81534002bcba42da97ab82b5d12aPaul Gortmaker#include <linux/module.h> 21c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/interrupt.h> 22c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/irq.h> 23c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/platform_device.h> 24b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar#include <linux/pm.h> 25c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/slab.h> 26c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/mmc/host.h> 27c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/mmc/sdhci-spear.h> 28c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include <linux/io.h> 29c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR#include "sdhci.h" 30c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 31c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstruct spear_sdhci { 32c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct clk *clk; 33c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct sdhci_plat_data *data; 34c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR}; 35c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 36c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR/* sdhci ops */ 37c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstatic struct sdhci_ops sdhci_pltfm_ops = { 38c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* Nothing to do for now. */ 39c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR}; 40c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 41c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR/* gpio card detection interrupt handler */ 42c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstatic irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) 43c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR{ 44c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct platform_device *pdev = dev_id; 45c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct sdhci_host *host = platform_get_drvdata(pdev); 46c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); 47c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR unsigned long gpio_irq_type; 48c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR int val; 49c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 50c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR val = gpio_get_value(sdhci->data->card_int_gpio); 51c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 52c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* val == 1 -> card removed, val == 0 -> card inserted */ 53c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* if card removed - set irq for low level, else vice versa */ 54c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; 55dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner irq_set_irq_type(irq, gpio_irq_type); 56c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 57c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_power_gpio >= 0) { 58c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!sdhci->data->power_always_enb) { 59c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* if card inserted, give power, otherwise remove it */ 60c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR val = sdhci->data->power_active_high ? !val : val ; 61c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_set_value(sdhci->data->card_power_gpio, val); 62c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 63c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 64c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 65c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* inform sdhci driver about card insertion/removal */ 66c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR tasklet_schedule(&host->card_tasklet); 67c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 68c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR return IRQ_HANDLED; 69c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR} 70c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 71c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstatic int __devinit sdhci_probe(struct platform_device *pdev) 72c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR{ 73c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct sdhci_host *host; 74c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct resource *iomem; 75c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct spear_sdhci *sdhci; 76c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR int ret; 77c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 78c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR BUG_ON(pdev == NULL); 79c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 80c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 81c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!iomem) { 82c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = -ENOMEM; 83c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "memory resource not defined\n"); 84c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err; 85c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 86c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 87c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!request_mem_region(iomem->start, resource_size(iomem), 88c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR "spear-sdhci")) { 89c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = -EBUSY; 90c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "cannot request region\n"); 91c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err; 92c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 93c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 94c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL); 95c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!sdhci) { 96c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = -ENOMEM; 97c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n"); 98c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_kzalloc; 99c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 100c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 101c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* clk enable */ 102c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->clk = clk_get(&pdev->dev, NULL); 103c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (IS_ERR(sdhci->clk)) { 104c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = PTR_ERR(sdhci->clk); 105c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "Error getting clock\n"); 106c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_clk_get; 107c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 108c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 109c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = clk_enable(sdhci->clk); 110c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret) { 111c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "Error enabling clock\n"); 112c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_clk_enb; 113c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 114c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 115c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* overwrite platform_data */ 116c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data = dev_get_platdata(&pdev->dev); 117c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR pdev->dev.platform_data = sdhci; 118c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 119c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (pdev->dev.parent) 120c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host = sdhci_alloc_host(pdev->dev.parent, 0); 121c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR else 122c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host = sdhci_alloc_host(&pdev->dev, 0); 123c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 124c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (IS_ERR(host)) { 125c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = PTR_ERR(host); 126c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "error allocating host\n"); 127c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_alloc_host; 128c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 129c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 130c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host->hw_name = "sdhci"; 131c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host->ops = &sdhci_pltfm_ops; 132c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host->irq = platform_get_irq(pdev, 0); 133c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host->quirks = SDHCI_QUIRK_BROKEN_ADMA; 134c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 135c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR host->ioaddr = ioremap(iomem->start, resource_size(iomem)); 136c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!host->ioaddr) { 137c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = -ENOMEM; 138c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "failed to remap registers\n"); 139c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_ioremap; 140c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 141c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 142c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = sdhci_add_host(host); 143c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret) { 144c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "error adding host\n"); 145c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_add_host; 146c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 147c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 148c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR platform_set_drvdata(pdev, host); 149c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 150c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR /* 151c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * It is optional to use GPIOs for sdhci Power control & sdhci card 152c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * interrupt detection. If sdhci->data is NULL, then use original sdhci 153c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * lines otherwise GPIO lines. 154c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * If GPIO is selected for power control, then power should be disabled 155c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * after card removal and should be enabled when card insertion 156c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR * interrupt occurs 157c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR */ 158c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (!sdhci->data) 159c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR return 0; 160c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 161c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_power_gpio >= 0) { 162c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR int val = 0; 163c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 164c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = gpio_request(sdhci->data->card_power_gpio, "sdhci"); 165c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret < 0) { 166c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "gpio request fail: %d\n", 167c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data->card_power_gpio); 168c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_pgpio_request; 169c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 170c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 171c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->power_always_enb) 172c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR val = sdhci->data->power_active_high; 173c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR else 174c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR val = !sdhci->data->power_active_high; 175c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 176c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = gpio_direction_output(sdhci->data->card_power_gpio, val); 177c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret) { 178c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 179c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data->card_power_gpio); 180c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_pgpio_direction; 181c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 182c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 183c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 184c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_int_gpio >= 0) { 185c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = gpio_request(sdhci->data->card_int_gpio, "sdhci"); 186c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret < 0) { 187c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "gpio request fail: %d\n", 188c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data->card_int_gpio); 189c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_igpio_request; 190c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 191c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 192c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = gpio_direction_input(sdhci->data->card_int_gpio); 193c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret) { 194c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "gpio set direction fail: %d\n", 195c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data->card_int_gpio); 196c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_igpio_direction; 197c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 198c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio), 199c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci_gpio_irq, IRQF_TRIGGER_LOW, 200c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR mmc_hostname(host->mmc), pdev); 201c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (ret) { 202c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_dbg(&pdev->dev, "gpio request irq fail: %d\n", 203c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci->data->card_int_gpio); 204c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR goto err_igpio_request_irq; 205c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 206c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 207c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 208c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 209c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR return 0; 210c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 211c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_igpio_request_irq: 212c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_igpio_direction: 213c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_int_gpio >= 0) 214c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_free(sdhci->data->card_int_gpio); 215c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_igpio_request: 216c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_pgpio_direction: 217c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_power_gpio >= 0) 218c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_free(sdhci->data->card_power_gpio); 219c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_pgpio_request: 220c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR platform_set_drvdata(pdev, NULL); 221c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci_remove_host(host, 1); 222c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_add_host: 223c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR iounmap(host->ioaddr); 224c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_ioremap: 225c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci_free_host(host); 226c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_alloc_host: 227c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR clk_disable(sdhci->clk); 228c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_clk_enb: 229c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR clk_put(sdhci->clk); 230c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_clk_get: 231c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR kfree(sdhci); 232c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr_kzalloc: 233c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR release_mem_region(iomem->start, resource_size(iomem)); 234c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARerr: 235c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); 236c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR return ret; 237c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR} 238c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 239c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstatic int __devexit sdhci_remove(struct platform_device *pdev) 240c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR{ 241c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct sdhci_host *host = platform_get_drvdata(pdev); 242c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 243c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); 244c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR int dead; 245c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR u32 scratch; 246c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 247c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data) { 248c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_int_gpio >= 0) { 249c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev); 250c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_free(sdhci->data->card_int_gpio); 251c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 252c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 253c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (sdhci->data->card_power_gpio >= 0) 254c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR gpio_free(sdhci->data->card_power_gpio); 255c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR } 256c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 257c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR platform_set_drvdata(pdev, NULL); 258c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dead = 0; 259c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR scratch = readl(host->ioaddr + SDHCI_INT_STATUS); 260c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (scratch == (u32)-1) 261c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR dead = 1; 262c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 263c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci_remove_host(host, dead); 264c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR iounmap(host->ioaddr); 265c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR sdhci_free_host(host); 266c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR clk_disable(sdhci->clk); 267c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR clk_put(sdhci->clk); 268c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR kfree(sdhci); 269c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR if (iomem) 270c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR release_mem_region(iomem->start, resource_size(iomem)); 271c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 272c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR return 0; 273c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR} 274c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 275b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar#ifdef CONFIG_PM 276b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumarstatic int sdhci_suspend(struct device *dev) 277b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar{ 278b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar struct sdhci_host *host = dev_get_drvdata(dev); 279b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar struct spear_sdhci *sdhci = dev_get_platdata(dev); 280b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar int ret; 281b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 282984589e59f5796b4ef9a778c6a1937fc9319c423Viresh Kumar ret = sdhci_suspend_host(host); 283b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar if (!ret) 284b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar clk_disable(sdhci->clk); 285b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 286b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar return ret; 287b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar} 288b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 289b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumarstatic int sdhci_resume(struct device *dev) 290b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar{ 291b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar struct sdhci_host *host = dev_get_drvdata(dev); 292b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar struct spear_sdhci *sdhci = dev_get_platdata(dev); 293b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar int ret; 294b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 295b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar ret = clk_enable(sdhci->clk); 296b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar if (ret) { 297b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar dev_dbg(dev, "Resume: Error enabling clock\n"); 298b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar return ret; 299b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar } 300b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 301b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar return sdhci_resume_host(host); 302b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar} 303b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar#endif 304b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar 3054b1a61705a563edb951b8fd9734bcb14286a7888Shiraz Hashimstatic SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume); 3064b1a61705a563edb951b8fd9734bcb14286a7888Shiraz Hashim 307c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARstatic struct platform_driver sdhci_driver = { 308c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR .driver = { 309c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR .name = "sdhci", 310c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR .owner = THIS_MODULE, 311b70a7fab26db65f7daaf04f49a3bd673250f48c7Viresh Kumar .pm = &sdhci_pm_ops, 312c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR }, 313c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR .probe = sdhci_probe, 314c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR .remove = __devexit_p(sdhci_remove), 315c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR}; 316c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 317d1f81a64a4250bdd776978be06ae2b8e13ec7471Axel Linmodule_platform_driver(sdhci_driver); 318c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMAR 319c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARMODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); 320c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARMODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); 321c63b3cba4f47ef9f4b3f952b4f923cf341d250acViresh KUMARMODULE_LICENSE("GPL v2"); 322