root/drivers/mmc/host/sdhci_f_sdh30.c

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

DEFINITIONS

This source file includes following definitions.
  1. sdhci_f_sdh30_soft_voltage_switch
  2. sdhci_f_sdh30_get_min_clock
  3. sdhci_f_sdh30_reset
  4. sdhci_f_sdh30_probe
  5. sdhci_f_sdh30_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/drivers/mmc/host/sdhci_f_sdh30.c
   4  *
   5  * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
   6  *              Vincent Yang <vincent.yang@tw.fujitsu.com>
   7  * Copyright (C) 2015 Linaro Ltd  Andy Green <andy.green@linaro.org>
   8  */
   9 
  10 #include <linux/acpi.h>
  11 #include <linux/err.h>
  12 #include <linux/delay.h>
  13 #include <linux/module.h>
  14 #include <linux/of.h>
  15 #include <linux/property.h>
  16 #include <linux/clk.h>
  17 
  18 #include "sdhci-pltfm.h"
  19 
  20 /* F_SDH30 extended Controller registers */
  21 #define F_SDH30_AHB_CONFIG              0x100
  22 #define  F_SDH30_AHB_BIGED              0x00000040
  23 #define  F_SDH30_BUSLOCK_DMA            0x00000020
  24 #define  F_SDH30_BUSLOCK_EN             0x00000010
  25 #define  F_SDH30_SIN                    0x00000008
  26 #define  F_SDH30_AHB_INCR_16            0x00000004
  27 #define  F_SDH30_AHB_INCR_8             0x00000002
  28 #define  F_SDH30_AHB_INCR_4             0x00000001
  29 
  30 #define F_SDH30_TUNING_SETTING          0x108
  31 #define  F_SDH30_CMD_CHK_DIS            0x00010000
  32 
  33 #define F_SDH30_IO_CONTROL2             0x114
  34 #define  F_SDH30_CRES_O_DN              0x00080000
  35 #define  F_SDH30_MSEL_O_1_8             0x00040000
  36 
  37 #define F_SDH30_ESD_CONTROL             0x124
  38 #define  F_SDH30_EMMC_RST               0x00000002
  39 #define  F_SDH30_EMMC_HS200             0x01000000
  40 
  41 #define F_SDH30_CMD_DAT_DELAY           0x200
  42 
  43 #define F_SDH30_MIN_CLOCK               400000
  44 
  45 struct f_sdhost_priv {
  46         struct clk *clk_iface;
  47         struct clk *clk;
  48         u32 vendor_hs200;
  49         struct device *dev;
  50         bool enable_cmd_dat_delay;
  51 };
  52 
  53 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
  54 {
  55         struct f_sdhost_priv *priv = sdhci_priv(host);
  56         u32 ctrl = 0;
  57 
  58         usleep_range(2500, 3000);
  59         ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
  60         ctrl |= F_SDH30_CRES_O_DN;
  61         sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
  62         ctrl |= F_SDH30_MSEL_O_1_8;
  63         sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
  64 
  65         ctrl &= ~F_SDH30_CRES_O_DN;
  66         sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
  67         usleep_range(2500, 3000);
  68 
  69         if (priv->vendor_hs200) {
  70                 dev_info(priv->dev, "%s: setting hs200\n", __func__);
  71                 ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
  72                 ctrl |= priv->vendor_hs200;
  73                 sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL);
  74         }
  75 
  76         ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
  77         ctrl |= F_SDH30_CMD_CHK_DIS;
  78         sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
  79 }
  80 
  81 static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
  82 {
  83         return F_SDH30_MIN_CLOCK;
  84 }
  85 
  86 static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
  87 {
  88         struct f_sdhost_priv *priv = sdhci_priv(host);
  89         u32 ctl;
  90 
  91         if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
  92                 sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
  93 
  94         sdhci_reset(host, mask);
  95 
  96         if (priv->enable_cmd_dat_delay) {
  97                 ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
  98                 ctl |= F_SDH30_CMD_DAT_DELAY;
  99                 sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
 100         }
 101 }
 102 
 103 static const struct sdhci_ops sdhci_f_sdh30_ops = {
 104         .voltage_switch = sdhci_f_sdh30_soft_voltage_switch,
 105         .get_min_clock = sdhci_f_sdh30_get_min_clock,
 106         .reset = sdhci_f_sdh30_reset,
 107         .set_clock = sdhci_set_clock,
 108         .set_bus_width = sdhci_set_bus_width,
 109         .set_uhs_signaling = sdhci_set_uhs_signaling,
 110 };
 111 
 112 static int sdhci_f_sdh30_probe(struct platform_device *pdev)
 113 {
 114         struct sdhci_host *host;
 115         struct device *dev = &pdev->dev;
 116         struct resource *res;
 117         int irq, ctrl = 0, ret = 0;
 118         struct f_sdhost_priv *priv;
 119         u32 reg = 0;
 120 
 121         irq = platform_get_irq(pdev, 0);
 122         if (irq < 0)
 123                 return irq;
 124 
 125         host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
 126         if (IS_ERR(host))
 127                 return PTR_ERR(host);
 128 
 129         priv = sdhci_priv(host);
 130         priv->dev = dev;
 131 
 132         host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 133                        SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
 134         host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
 135                         SDHCI_QUIRK2_TUNING_WORK_AROUND;
 136 
 137         priv->enable_cmd_dat_delay = device_property_read_bool(dev,
 138                                                 "fujitsu,cmd-dat-delay-select");
 139 
 140         ret = mmc_of_parse(host->mmc);
 141         if (ret)
 142                 goto err;
 143 
 144         platform_set_drvdata(pdev, host);
 145 
 146         host->hw_name = "f_sdh30";
 147         host->ops = &sdhci_f_sdh30_ops;
 148         host->irq = irq;
 149 
 150         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 151         host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
 152         if (IS_ERR(host->ioaddr)) {
 153                 ret = PTR_ERR(host->ioaddr);
 154                 goto err;
 155         }
 156 
 157         if (dev_of_node(dev)) {
 158                 sdhci_get_of_property(pdev);
 159 
 160                 priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
 161                 if (IS_ERR(priv->clk_iface)) {
 162                         ret = PTR_ERR(priv->clk_iface);
 163                         goto err;
 164                 }
 165 
 166                 ret = clk_prepare_enable(priv->clk_iface);
 167                 if (ret)
 168                         goto err;
 169 
 170                 priv->clk = devm_clk_get(&pdev->dev, "core");
 171                 if (IS_ERR(priv->clk)) {
 172                         ret = PTR_ERR(priv->clk);
 173                         goto err_clk;
 174                 }
 175 
 176                 ret = clk_prepare_enable(priv->clk);
 177                 if (ret)
 178                         goto err_clk;
 179         }
 180 
 181         /* init vendor specific regs */
 182         ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
 183         ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
 184                 F_SDH30_AHB_INCR_4;
 185         ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
 186         sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG);
 187 
 188         reg = sdhci_readl(host, F_SDH30_ESD_CONTROL);
 189         sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
 190         msleep(20);
 191         sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
 192 
 193         reg = sdhci_readl(host, SDHCI_CAPABILITIES);
 194         if (reg & SDHCI_CAN_DO_8BIT)
 195                 priv->vendor_hs200 = F_SDH30_EMMC_HS200;
 196 
 197         ret = sdhci_add_host(host);
 198         if (ret)
 199                 goto err_add_host;
 200 
 201         return 0;
 202 
 203 err_add_host:
 204         clk_disable_unprepare(priv->clk);
 205 err_clk:
 206         clk_disable_unprepare(priv->clk_iface);
 207 err:
 208         sdhci_free_host(host);
 209         return ret;
 210 }
 211 
 212 static int sdhci_f_sdh30_remove(struct platform_device *pdev)
 213 {
 214         struct sdhci_host *host = platform_get_drvdata(pdev);
 215         struct f_sdhost_priv *priv = sdhci_priv(host);
 216 
 217         sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
 218                           0xffffffff);
 219 
 220         clk_disable_unprepare(priv->clk_iface);
 221         clk_disable_unprepare(priv->clk);
 222 
 223         sdhci_free_host(host);
 224         platform_set_drvdata(pdev, NULL);
 225 
 226         return 0;
 227 }
 228 
 229 #ifdef CONFIG_OF
 230 static const struct of_device_id f_sdh30_dt_ids[] = {
 231         { .compatible = "fujitsu,mb86s70-sdhci-3.0" },
 232         { /* sentinel */ }
 233 };
 234 MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
 235 #endif
 236 
 237 #ifdef CONFIG_ACPI
 238 static const struct acpi_device_id f_sdh30_acpi_ids[] = {
 239         { "SCX0002" },
 240         { /* sentinel */ }
 241 };
 242 MODULE_DEVICE_TABLE(acpi, f_sdh30_acpi_ids);
 243 #endif
 244 
 245 static struct platform_driver sdhci_f_sdh30_driver = {
 246         .driver = {
 247                 .name = "f_sdh30",
 248                 .of_match_table = of_match_ptr(f_sdh30_dt_ids),
 249                 .acpi_match_table = ACPI_PTR(f_sdh30_acpi_ids),
 250                 .pm     = &sdhci_pltfm_pmops,
 251         },
 252         .probe  = sdhci_f_sdh30_probe,
 253         .remove = sdhci_f_sdh30_remove,
 254 };
 255 
 256 module_platform_driver(sdhci_f_sdh30_driver);
 257 
 258 MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
 259 MODULE_LICENSE("GPL v2");
 260 MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
 261 MODULE_ALIAS("platform:f_sdh30");

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