1985b1aa0SMike Rapoport /* 2985b1aa0SMike Rapoport * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC 3985b1aa0SMike Rapoport * 4985b1aa0SMike Rapoport * Author: Saeed Bishara <saeed@marvell.com> 5985b1aa0SMike Rapoport * Mike Rapoport <mike@compulab.co.il> 6985b1aa0SMike Rapoport * Based on sdhci-cns3xxx.c 7985b1aa0SMike Rapoport * 8985b1aa0SMike Rapoport * This program is free software; you can redistribute it and/or modify 9985b1aa0SMike Rapoport * it under the terms of the GNU General Public License version 2 as 10985b1aa0SMike Rapoport * published by the Free Software Foundation. 11985b1aa0SMike Rapoport * 12985b1aa0SMike Rapoport * This program is distributed in the hope that it will be useful, 13985b1aa0SMike Rapoport * but WITHOUT ANY WARRANTY; without even the implied warranty of 14985b1aa0SMike Rapoport * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15985b1aa0SMike Rapoport * GNU General Public License for more details. 16985b1aa0SMike Rapoport * 17985b1aa0SMike Rapoport * You should have received a copy of the GNU General Public License 18985b1aa0SMike Rapoport * along with this program; if not, write to the Free Software 19985b1aa0SMike Rapoport * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20985b1aa0SMike Rapoport */ 21985b1aa0SMike Rapoport 22ee3298a2SRussell King - ARM Linux #include <linux/err.h> 23985b1aa0SMike Rapoport #include <linux/io.h> 2430b87c60SSebastian Hesselbarth #include <linux/clk.h> 2530b87c60SSebastian Hesselbarth #include <linux/err.h> 268c2fc8e4SAlf Høgemark #include <linux/module.h> 27985b1aa0SMike Rapoport #include <linux/mmc/host.h> 284ee7ed0dSSebastian Hesselbarth #include <linux/of.h> 29985b1aa0SMike Rapoport 30985b1aa0SMike Rapoport #include "sdhci-pltfm.h" 31985b1aa0SMike Rapoport 3230b87c60SSebastian Hesselbarth struct sdhci_dove_priv { 3330b87c60SSebastian Hesselbarth struct clk *clk; 3430b87c60SSebastian Hesselbarth }; 3530b87c60SSebastian Hesselbarth 36985b1aa0SMike Rapoport static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) 37985b1aa0SMike Rapoport { 38985b1aa0SMike Rapoport u16 ret; 39985b1aa0SMike Rapoport 40985b1aa0SMike Rapoport switch (reg) { 41985b1aa0SMike Rapoport case SDHCI_HOST_VERSION: 42985b1aa0SMike Rapoport case SDHCI_SLOT_INT_STATUS: 43985b1aa0SMike Rapoport /* those registers don't exist */ 44985b1aa0SMike Rapoport return 0; 45985b1aa0SMike Rapoport default: 46985b1aa0SMike Rapoport ret = readw(host->ioaddr + reg); 47985b1aa0SMike Rapoport } 48985b1aa0SMike Rapoport return ret; 49985b1aa0SMike Rapoport } 50985b1aa0SMike Rapoport 51985b1aa0SMike Rapoport static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) 52985b1aa0SMike Rapoport { 53985b1aa0SMike Rapoport u32 ret; 54985b1aa0SMike Rapoport 55985b1aa0SMike Rapoport switch (reg) { 56985b1aa0SMike Rapoport case SDHCI_CAPABILITIES: 57985b1aa0SMike Rapoport ret = readl(host->ioaddr + reg); 58985b1aa0SMike Rapoport /* Mask the support for 3.0V */ 59985b1aa0SMike Rapoport ret &= ~SDHCI_CAN_VDD_300; 60985b1aa0SMike Rapoport break; 61985b1aa0SMike Rapoport default: 62985b1aa0SMike Rapoport ret = readl(host->ioaddr + reg); 63985b1aa0SMike Rapoport } 64985b1aa0SMike Rapoport return ret; 65985b1aa0SMike Rapoport } 66985b1aa0SMike Rapoport 67985b1aa0SMike Rapoport static struct sdhci_ops sdhci_dove_ops = { 68985b1aa0SMike Rapoport .read_w = sdhci_dove_readw, 69985b1aa0SMike Rapoport .read_l = sdhci_dove_readl, 70985b1aa0SMike Rapoport }; 71985b1aa0SMike Rapoport 7285d6509dSShawn Guo static struct sdhci_pltfm_data sdhci_dove_pdata = { 73985b1aa0SMike Rapoport .ops = &sdhci_dove_ops, 74985b1aa0SMike Rapoport .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | 75985b1aa0SMike Rapoport SDHCI_QUIRK_NO_BUSY_IRQ | 76985b1aa0SMike Rapoport SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 77a9ca1d54SSebastian Hesselbarth SDHCI_QUIRK_FORCE_DMA | 78a9ca1d54SSebastian Hesselbarth SDHCI_QUIRK_NO_HISPD_BIT, 79985b1aa0SMike Rapoport }; 8085d6509dSShawn Guo 8185d6509dSShawn Guo static int __devinit sdhci_dove_probe(struct platform_device *pdev) 8285d6509dSShawn Guo { 8330b87c60SSebastian Hesselbarth struct sdhci_host *host; 8430b87c60SSebastian Hesselbarth struct sdhci_pltfm_host *pltfm_host; 8530b87c60SSebastian Hesselbarth struct sdhci_dove_priv *priv; 8630b87c60SSebastian Hesselbarth int ret; 8730b87c60SSebastian Hesselbarth 8830b87c60SSebastian Hesselbarth priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv), 8930b87c60SSebastian Hesselbarth GFP_KERNEL); 9030b87c60SSebastian Hesselbarth if (!priv) { 9130b87c60SSebastian Hesselbarth dev_err(&pdev->dev, "unable to allocate private data"); 92ee3298a2SRussell King - ARM Linux return -ENOMEM; 9330b87c60SSebastian Hesselbarth } 9430b87c60SSebastian Hesselbarth 957430e77eSRussell King priv->clk = devm_clk_get(&pdev->dev, NULL); 96ee3298a2SRussell King - ARM Linux 97c430689fSRussell King host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata); 98c430689fSRussell King if (IS_ERR(host)) { 99c430689fSRussell King ret = PTR_ERR(host); 100c430689fSRussell King goto err_sdhci_pltfm_init; 101c430689fSRussell King } 102ee3298a2SRussell King - ARM Linux 10330b87c60SSebastian Hesselbarth pltfm_host = sdhci_priv(host); 10430b87c60SSebastian Hesselbarth pltfm_host->priv = priv; 10530b87c60SSebastian Hesselbarth 106c430689fSRussell King if (!IS_ERR(priv->clk)) 107c430689fSRussell King clk_prepare_enable(priv->clk); 108c430689fSRussell King 109c430689fSRussell King sdhci_get_of_property(pdev); 110c430689fSRussell King 111c430689fSRussell King ret = sdhci_add_host(host); 112c430689fSRussell King if (ret) 113c430689fSRussell King goto err_sdhci_add; 114c430689fSRussell King 11530b87c60SSebastian Hesselbarth return 0; 11630b87c60SSebastian Hesselbarth 117c430689fSRussell King err_sdhci_add: 1187430e77eSRussell King if (!IS_ERR(priv->clk)) 119ee3298a2SRussell King - ARM Linux clk_disable_unprepare(priv->clk); 120c430689fSRussell King sdhci_pltfm_free(pdev); 121c430689fSRussell King err_sdhci_pltfm_init: 12230b87c60SSebastian Hesselbarth return ret; 12385d6509dSShawn Guo } 12485d6509dSShawn Guo 12585d6509dSShawn Guo static int __devexit sdhci_dove_remove(struct platform_device *pdev) 12685d6509dSShawn Guo { 12730b87c60SSebastian Hesselbarth struct sdhci_host *host = platform_get_drvdata(pdev); 12830b87c60SSebastian Hesselbarth struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 12930b87c60SSebastian Hesselbarth struct sdhci_dove_priv *priv = pltfm_host->priv; 13030b87c60SSebastian Hesselbarth 131ee3298a2SRussell King - ARM Linux sdhci_pltfm_unregister(pdev); 132ee3298a2SRussell King - ARM Linux 1337430e77eSRussell King if (!IS_ERR(priv->clk)) 13430b87c60SSebastian Hesselbarth clk_disable_unprepare(priv->clk); 1357430e77eSRussell King 136ee3298a2SRussell King - ARM Linux return 0; 13785d6509dSShawn Guo } 13885d6509dSShawn Guo 1394ee7ed0dSSebastian Hesselbarth static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = { 1404ee7ed0dSSebastian Hesselbarth { .compatible = "marvell,dove-sdhci", }, 1414ee7ed0dSSebastian Hesselbarth {} 1424ee7ed0dSSebastian Hesselbarth }; 1434ee7ed0dSSebastian Hesselbarth MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table); 1444ee7ed0dSSebastian Hesselbarth 14585d6509dSShawn Guo static struct platform_driver sdhci_dove_driver = { 14685d6509dSShawn Guo .driver = { 14785d6509dSShawn Guo .name = "sdhci-dove", 14885d6509dSShawn Guo .owner = THIS_MODULE, 14929495aa0SManuel Lauss .pm = SDHCI_PLTFM_PMOPS, 1504ee7ed0dSSebastian Hesselbarth .of_match_table = of_match_ptr(sdhci_dove_of_match_table), 15185d6509dSShawn Guo }, 15285d6509dSShawn Guo .probe = sdhci_dove_probe, 15385d6509dSShawn Guo .remove = __devexit_p(sdhci_dove_remove), 15485d6509dSShawn Guo }; 15585d6509dSShawn Guo 156d1f81a64SAxel Lin module_platform_driver(sdhci_dove_driver); 15785d6509dSShawn Guo 15885d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Dove"); 15985d6509dSShawn Guo MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, " 16085d6509dSShawn Guo "Mike Rapoport <mike@compulab.co.il>"); 16185d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 162