root/drivers/mmc/host/tmio_mmc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tmio_mmc_clk_start
  2. tmio_mmc_clk_stop
  3. tmio_mmc_set_clock
  4. tmio_mmc_reset
  5. tmio_mmc_suspend
  6. tmio_mmc_resume
  7. tmio_mmc_probe
  8. tmio_mmc_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Driver for the MMC / SD / SDIO cell found in:
   4  *
   5  * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
   6  *
   7  * Copyright (C) 2017 Renesas Electronics Corporation
   8  * Copyright (C) 2017 Horms Solutions, Simon Horman
   9  * Copyright (C) 2007 Ian Molton
  10  * Copyright (C) 2004 Ian Molton
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/device.h>
  15 #include <linux/mfd/core.h>
  16 #include <linux/mfd/tmio.h>
  17 #include <linux/mmc/host.h>
  18 #include <linux/module.h>
  19 #include <linux/pagemap.h>
  20 #include <linux/scatterlist.h>
  21 
  22 #include "tmio_mmc.h"
  23 
  24 /* Registers specific to this variant */
  25 #define CTL_SDIO_REGS           0x100
  26 #define CTL_CLK_AND_WAIT_CTL    0x138
  27 #define CTL_RESET_SDIO          0x1e0
  28 
  29 static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
  30 {
  31         sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
  32                 sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
  33 
  34         usleep_range(10000, 11000);
  35         sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
  36         usleep_range(10000, 11000);
  37 }
  38 
  39 static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
  40 {
  41         sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
  42         usleep_range(10000, 11000);
  43 
  44         sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
  45                 sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
  46 
  47         usleep_range(10000, 11000);
  48 }
  49 
  50 static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
  51                                unsigned int new_clock)
  52 {
  53         unsigned int divisor;
  54         u32 clk = 0;
  55         int clk_sel;
  56 
  57         if (new_clock == 0) {
  58                 tmio_mmc_clk_stop(host);
  59                 return;
  60         }
  61 
  62         divisor = host->pdata->hclk / new_clock;
  63 
  64         /* bit7 set: 1/512, ... bit0 set: 1/4, all bits clear: 1/2 */
  65         clk_sel = (divisor <= 1);
  66         clk = clk_sel ? 0 : (roundup_pow_of_two(divisor) >> 2);
  67 
  68         host->pdata->set_clk_div(host->pdev, clk_sel);
  69 
  70         sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
  71                         sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
  72         sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
  73         usleep_range(10000, 11000);
  74 
  75         tmio_mmc_clk_start(host);
  76 }
  77 
  78 static void tmio_mmc_reset(struct tmio_mmc_host *host)
  79 {
  80         /* FIXME - should we set stop clock reg here */
  81         sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
  82         sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
  83         usleep_range(10000, 11000);
  84         sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
  85         sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
  86         usleep_range(10000, 11000);
  87 
  88         if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
  89                 sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
  90                 sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
  91         }
  92 }
  93 
  94 #ifdef CONFIG_PM_SLEEP
  95 static int tmio_mmc_suspend(struct device *dev)
  96 {
  97         struct platform_device *pdev = to_platform_device(dev);
  98         const struct mfd_cell *cell = mfd_get_cell(pdev);
  99         int ret;
 100 
 101         ret = pm_runtime_force_suspend(dev);
 102 
 103         /* Tell MFD core it can disable us now.*/
 104         if (!ret && cell->disable)
 105                 cell->disable(pdev);
 106 
 107         return ret;
 108 }
 109 
 110 static int tmio_mmc_resume(struct device *dev)
 111 {
 112         struct platform_device *pdev = to_platform_device(dev);
 113         const struct mfd_cell *cell = mfd_get_cell(pdev);
 114         int ret = 0;
 115 
 116         /* Tell the MFD core we are ready to be enabled */
 117         if (cell->resume)
 118                 ret = cell->resume(pdev);
 119 
 120         if (!ret)
 121                 ret = pm_runtime_force_resume(dev);
 122 
 123         return ret;
 124 }
 125 #endif
 126 
 127 static int tmio_mmc_probe(struct platform_device *pdev)
 128 {
 129         const struct mfd_cell *cell = mfd_get_cell(pdev);
 130         struct tmio_mmc_data *pdata;
 131         struct tmio_mmc_host *host;
 132         struct resource *res;
 133         int ret = -EINVAL, irq;
 134 
 135         if (pdev->num_resources != 2)
 136                 goto out;
 137 
 138         pdata = pdev->dev.platform_data;
 139         if (!pdata || !pdata->hclk)
 140                 goto out;
 141 
 142         irq = platform_get_irq(pdev, 0);
 143         if (irq < 0) {
 144                 ret = irq;
 145                 goto out;
 146         }
 147 
 148         /* Tell the MFD core we are ready to be enabled */
 149         if (cell->enable) {
 150                 ret = cell->enable(pdev);
 151                 if (ret)
 152                         goto out;
 153         }
 154 
 155         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 156         if (!res) {
 157                 ret = -EINVAL;
 158                 goto cell_disable;
 159         }
 160 
 161         host = tmio_mmc_host_alloc(pdev, pdata);
 162         if (IS_ERR(host)) {
 163                 ret = PTR_ERR(host);
 164                 goto cell_disable;
 165         }
 166 
 167         /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
 168         host->bus_shift = resource_size(res) >> 10;
 169         host->set_clock = tmio_mmc_set_clock;
 170         host->reset = tmio_mmc_reset;
 171 
 172         host->mmc->f_max = pdata->hclk;
 173         host->mmc->f_min = pdata->hclk / 512;
 174 
 175         ret = tmio_mmc_host_probe(host);
 176         if (ret)
 177                 goto host_free;
 178 
 179         ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq,
 180                                IRQF_TRIGGER_FALLING,
 181                                dev_name(&pdev->dev), host);
 182         if (ret)
 183                 goto host_remove;
 184 
 185         pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
 186                 (unsigned long)host->ctl, irq);
 187 
 188         return 0;
 189 
 190 host_remove:
 191         tmio_mmc_host_remove(host);
 192 host_free:
 193         tmio_mmc_host_free(host);
 194 cell_disable:
 195         if (cell->disable)
 196                 cell->disable(pdev);
 197 out:
 198         return ret;
 199 }
 200 
 201 static int tmio_mmc_remove(struct platform_device *pdev)
 202 {
 203         const struct mfd_cell *cell = mfd_get_cell(pdev);
 204         struct tmio_mmc_host *host = platform_get_drvdata(pdev);
 205 
 206         tmio_mmc_host_remove(host);
 207         if (cell->disable)
 208                 cell->disable(pdev);
 209 
 210         return 0;
 211 }
 212 
 213 /* ------------------- device registration ----------------------- */
 214 
 215 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
 216         SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
 217         SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
 218                            tmio_mmc_host_runtime_resume, NULL)
 219 };
 220 
 221 static struct platform_driver tmio_mmc_driver = {
 222         .driver = {
 223                 .name = "tmio-mmc",
 224                 .pm = &tmio_mmc_dev_pm_ops,
 225         },
 226         .probe = tmio_mmc_probe,
 227         .remove = tmio_mmc_remove,
 228 };
 229 
 230 module_platform_driver(tmio_mmc_driver);
 231 
 232 MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
 233 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 234 MODULE_LICENSE("GPL v2");
 235 MODULE_ALIAS("platform:tmio-mmc");

/* [<][>][^][v][top][bottom][index][help] */