root/drivers/mmc/host/sdhci-pic32.c

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

DEFINITIONS

This source file includes following definitions.
  1. pic32_sdhci_get_max_clock
  2. pic32_sdhci_set_bus_width
  3. pic32_sdhci_get_ro
  4. pic32_sdhci_shared_bus
  5. pic32_sdhci_probe_platform
  6. pic32_sdhci_probe
  7. pic32_sdhci_remove

   1 /*
   2  * Support of SDHCI platform devices for Microchip PIC32.
   3  *
   4  * Copyright (C) 2015 Microchip
   5  * Andrei Pistirica, Paul Thacker
   6  *
   7  * Inspired by sdhci-pltfm.c
   8  *
   9  * This file is licensed under the terms of the GNU General Public
  10  * License version 2. This program is licensed "as is" without any
  11  * warranty of any kind, whether express or implied.
  12  */
  13 
  14 #include <linux/clk.h>
  15 #include <linux/delay.h>
  16 #include <linux/highmem.h>
  17 #include <linux/module.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/irq.h>
  20 #include <linux/of.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/pm.h>
  23 #include <linux/slab.h>
  24 #include <linux/mmc/host.h>
  25 #include <linux/io.h>
  26 #include "sdhci.h"
  27 #include "sdhci-pltfm.h"
  28 #include <linux/platform_data/sdhci-pic32.h>
  29 
  30 #define SDH_SHARED_BUS_CTRL             0x000000E0
  31 #define SDH_SHARED_BUS_NR_CLK_PINS_MASK 0x7
  32 #define SDH_SHARED_BUS_NR_IRQ_PINS_MASK 0x30
  33 #define SDH_SHARED_BUS_CLK_PINS         0x10
  34 #define SDH_SHARED_BUS_IRQ_PINS         0x14
  35 #define SDH_CAPS_SDH_SLOT_TYPE_MASK     0xC0000000
  36 #define SDH_SLOT_TYPE_REMOVABLE         0x0
  37 #define SDH_SLOT_TYPE_EMBEDDED          0x1
  38 #define SDH_SLOT_TYPE_SHARED_BUS        0x2
  39 #define SDHCI_CTRL_CDSSEL               0x80
  40 #define SDHCI_CTRL_CDTLVL               0x40
  41 
  42 #define ADMA_FIFO_RD_THSHLD     512
  43 #define ADMA_FIFO_WR_THSHLD     512
  44 
  45 struct pic32_sdhci_priv {
  46         struct platform_device  *pdev;
  47         struct clk *sys_clk;
  48         struct clk *base_clk;
  49 };
  50 
  51 static unsigned int pic32_sdhci_get_max_clock(struct sdhci_host *host)
  52 {
  53         struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host);
  54 
  55         return clk_get_rate(sdhci_pdata->base_clk);
  56 }
  57 
  58 static void pic32_sdhci_set_bus_width(struct sdhci_host *host, int width)
  59 {
  60         u8 ctrl;
  61 
  62         ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
  63         if (width == MMC_BUS_WIDTH_8) {
  64                 ctrl &= ~SDHCI_CTRL_4BITBUS;
  65                 if (host->version >= SDHCI_SPEC_300)
  66                         ctrl |= SDHCI_CTRL_8BITBUS;
  67         } else {
  68                 if (host->version >= SDHCI_SPEC_300)
  69                         ctrl &= ~SDHCI_CTRL_8BITBUS;
  70                 if (width == MMC_BUS_WIDTH_4)
  71                         ctrl |= SDHCI_CTRL_4BITBUS;
  72                 else
  73                         ctrl &= ~SDHCI_CTRL_4BITBUS;
  74         }
  75 
  76         /* CD select and test bits must be set for errata workaround. */
  77         ctrl &= ~SDHCI_CTRL_CDTLVL;
  78         ctrl |= SDHCI_CTRL_CDSSEL;
  79         sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
  80 }
  81 
  82 static unsigned int pic32_sdhci_get_ro(struct sdhci_host *host)
  83 {
  84         /*
  85          * The SDHCI_WRITE_PROTECT bit is unstable on current hardware so we
  86          * can't depend on its value in any way.
  87          */
  88         return 0;
  89 }
  90 
  91 static const struct sdhci_ops pic32_sdhci_ops = {
  92         .get_max_clock = pic32_sdhci_get_max_clock,
  93         .set_clock = sdhci_set_clock,
  94         .set_bus_width = pic32_sdhci_set_bus_width,
  95         .reset = sdhci_reset,
  96         .set_uhs_signaling = sdhci_set_uhs_signaling,
  97         .get_ro = pic32_sdhci_get_ro,
  98 };
  99 
 100 static const struct sdhci_pltfm_data sdhci_pic32_pdata = {
 101         .ops = &pic32_sdhci_ops,
 102         .quirks = SDHCI_QUIRK_NO_HISPD_BIT,
 103         .quirks2 = SDHCI_QUIRK2_NO_1_8_V,
 104 };
 105 
 106 static void pic32_sdhci_shared_bus(struct platform_device *pdev)
 107 {
 108         struct sdhci_host *host = platform_get_drvdata(pdev);
 109         u32 bus = readl(host->ioaddr + SDH_SHARED_BUS_CTRL);
 110         u32 clk_pins = (bus & SDH_SHARED_BUS_NR_CLK_PINS_MASK) >> 0;
 111         u32 irq_pins = (bus & SDH_SHARED_BUS_NR_IRQ_PINS_MASK) >> 4;
 112 
 113         /* select first clock */
 114         if (clk_pins & 1)
 115                 bus |= (1 << SDH_SHARED_BUS_CLK_PINS);
 116 
 117         /* select first interrupt */
 118         if (irq_pins & 1)
 119                 bus |= (1 << SDH_SHARED_BUS_IRQ_PINS);
 120 
 121         writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL);
 122 }
 123 
 124 static int pic32_sdhci_probe_platform(struct platform_device *pdev,
 125                                       struct pic32_sdhci_priv *pdata)
 126 {
 127         int ret = 0;
 128         u32 caps_slot_type;
 129         struct sdhci_host *host = platform_get_drvdata(pdev);
 130 
 131         /* Check card slot connected on shared bus. */
 132         host->caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 133         caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30;
 134         if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS)
 135                 pic32_sdhci_shared_bus(pdev);
 136 
 137         return ret;
 138 }
 139 
 140 static int pic32_sdhci_probe(struct platform_device *pdev)
 141 {
 142         struct sdhci_host *host;
 143         struct sdhci_pltfm_host *pltfm_host;
 144         struct pic32_sdhci_priv *sdhci_pdata;
 145         struct pic32_sdhci_platform_data *plat_data;
 146         int ret;
 147 
 148         host = sdhci_pltfm_init(pdev, &sdhci_pic32_pdata,
 149                                 sizeof(struct pic32_sdhci_priv));
 150         if (IS_ERR(host)) {
 151                 ret = PTR_ERR(host);
 152                 goto err;
 153         }
 154 
 155         pltfm_host = sdhci_priv(host);
 156         sdhci_pdata = sdhci_pltfm_priv(pltfm_host);
 157 
 158         plat_data = pdev->dev.platform_data;
 159         if (plat_data && plat_data->setup_dma) {
 160                 ret = plat_data->setup_dma(ADMA_FIFO_RD_THSHLD,
 161                                            ADMA_FIFO_WR_THSHLD);
 162                 if (ret)
 163                         goto err_host;
 164         }
 165 
 166         sdhci_pdata->sys_clk = devm_clk_get(&pdev->dev, "sys_clk");
 167         if (IS_ERR(sdhci_pdata->sys_clk)) {
 168                 ret = PTR_ERR(sdhci_pdata->sys_clk);
 169                 dev_err(&pdev->dev, "Error getting clock\n");
 170                 goto err_host;
 171         }
 172 
 173         ret = clk_prepare_enable(sdhci_pdata->sys_clk);
 174         if (ret) {
 175                 dev_err(&pdev->dev, "Error enabling clock\n");
 176                 goto err_host;
 177         }
 178 
 179         sdhci_pdata->base_clk = devm_clk_get(&pdev->dev, "base_clk");
 180         if (IS_ERR(sdhci_pdata->base_clk)) {
 181                 ret = PTR_ERR(sdhci_pdata->base_clk);
 182                 dev_err(&pdev->dev, "Error getting clock\n");
 183                 goto err_sys_clk;
 184         }
 185 
 186         ret = clk_prepare_enable(sdhci_pdata->base_clk);
 187         if (ret) {
 188                 dev_err(&pdev->dev, "Error enabling clock\n");
 189                 goto err_base_clk;
 190         }
 191 
 192         ret = mmc_of_parse(host->mmc);
 193         if (ret)
 194                 goto err_base_clk;
 195 
 196         ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata);
 197         if (ret) {
 198                 dev_err(&pdev->dev, "failed to probe platform!\n");
 199                 goto err_base_clk;
 200         }
 201 
 202         ret = sdhci_add_host(host);
 203         if (ret)
 204                 goto err_base_clk;
 205 
 206         dev_info(&pdev->dev, "Successfully added sdhci host\n");
 207         return 0;
 208 
 209 err_base_clk:
 210         clk_disable_unprepare(sdhci_pdata->base_clk);
 211 err_sys_clk:
 212         clk_disable_unprepare(sdhci_pdata->sys_clk);
 213 err_host:
 214         sdhci_pltfm_free(pdev);
 215 err:
 216         dev_err(&pdev->dev, "pic32-sdhci probe failed: %d\n", ret);
 217         return ret;
 218 }
 219 
 220 static int pic32_sdhci_remove(struct platform_device *pdev)
 221 {
 222         struct sdhci_host *host = platform_get_drvdata(pdev);
 223         struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host);
 224         u32 scratch;
 225 
 226         scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
 227         sdhci_remove_host(host, scratch == (u32)~0);
 228         clk_disable_unprepare(sdhci_pdata->base_clk);
 229         clk_disable_unprepare(sdhci_pdata->sys_clk);
 230         sdhci_pltfm_free(pdev);
 231 
 232         return 0;
 233 }
 234 
 235 static const struct of_device_id pic32_sdhci_id_table[] = {
 236         { .compatible = "microchip,pic32mzda-sdhci" },
 237         {}
 238 };
 239 MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table);
 240 
 241 static struct platform_driver pic32_sdhci_driver = {
 242         .driver = {
 243                 .name   = "pic32-sdhci",
 244                 .of_match_table = of_match_ptr(pic32_sdhci_id_table),
 245         },
 246         .probe          = pic32_sdhci_probe,
 247         .remove         = pic32_sdhci_remove,
 248 };
 249 
 250 module_platform_driver(pic32_sdhci_driver);
 251 
 252 MODULE_DESCRIPTION("Microchip PIC32 SDHCI driver");
 253 MODULE_AUTHOR("Pistirica Sorin Andrei & Sandeep Sheriker");
 254 MODULE_LICENSE("GPL v2");

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