2 * Support of SDHCI platform devices for Microchip PIC32.
4 * Copyright (C) 2015 Microchip
5 * Andrei Pistirica, Paul Thacker
7 * Inspired by sdhci-pltfm.c
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.
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>
21 #include <linux/platform_device.h>
23 #include <linux/slab.h>
24 #include <linux/mmc/host.h>
27 #include "sdhci-pltfm.h"
28 #include <linux/platform_data/sdhci-pic32.h>
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
42 #define ADMA_FIFO_RD_THSHLD 512
43 #define ADMA_FIFO_WR_THSHLD 512
45 struct pic32_sdhci_priv
{
46 struct platform_device
*pdev
;
51 static unsigned int pic32_sdhci_get_max_clock(struct sdhci_host
*host
)
53 struct pic32_sdhci_priv
*sdhci_pdata
= sdhci_priv(host
);
55 return clk_get_rate(sdhci_pdata
->base_clk
);
58 static void pic32_sdhci_set_bus_width(struct sdhci_host
*host
, int width
)
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
;
68 if (host
->version
>= SDHCI_SPEC_300
)
69 ctrl
&= ~SDHCI_CTRL_8BITBUS
;
70 if (width
== MMC_BUS_WIDTH_4
)
71 ctrl
|= SDHCI_CTRL_4BITBUS
;
73 ctrl
&= ~SDHCI_CTRL_4BITBUS
;
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
);
82 static unsigned int pic32_sdhci_get_ro(struct sdhci_host
*host
)
85 * The SDHCI_WRITE_PROTECT bit is unstable on current hardware so we
86 * can't depend on its value in any way.
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
,
96 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
97 .get_ro
= pic32_sdhci_get_ro
,
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
,
106 static void pic32_sdhci_shared_bus(struct platform_device
*pdev
)
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;
113 /* select first clock */
115 bus
|= (1 << SDH_SHARED_BUS_CLK_PINS
);
117 /* select first interrupt */
119 bus
|= (1 << SDH_SHARED_BUS_IRQ_PINS
);
121 writel(bus
, host
->ioaddr
+ SDH_SHARED_BUS_CTRL
);
124 static void pic32_sdhci_probe_platform(struct platform_device
*pdev
,
125 struct pic32_sdhci_priv
*pdata
)
128 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
130 /* Check card slot connected on shared bus. */
131 host
->caps
= readl(host
->ioaddr
+ SDHCI_CAPABILITIES
);
132 caps_slot_type
= (host
->caps
& SDH_CAPS_SDH_SLOT_TYPE_MASK
) >> 30;
133 if (caps_slot_type
== SDH_SLOT_TYPE_SHARED_BUS
)
134 pic32_sdhci_shared_bus(pdev
);
137 static int pic32_sdhci_probe(struct platform_device
*pdev
)
139 struct sdhci_host
*host
;
140 struct sdhci_pltfm_host
*pltfm_host
;
141 struct pic32_sdhci_priv
*sdhci_pdata
;
142 struct pic32_sdhci_platform_data
*plat_data
;
145 host
= sdhci_pltfm_init(pdev
, &sdhci_pic32_pdata
,
146 sizeof(struct pic32_sdhci_priv
));
152 pltfm_host
= sdhci_priv(host
);
153 sdhci_pdata
= sdhci_pltfm_priv(pltfm_host
);
155 plat_data
= pdev
->dev
.platform_data
;
156 if (plat_data
&& plat_data
->setup_dma
) {
157 ret
= plat_data
->setup_dma(ADMA_FIFO_RD_THSHLD
,
158 ADMA_FIFO_WR_THSHLD
);
163 sdhci_pdata
->sys_clk
= devm_clk_get(&pdev
->dev
, "sys_clk");
164 if (IS_ERR(sdhci_pdata
->sys_clk
)) {
165 ret
= PTR_ERR(sdhci_pdata
->sys_clk
);
166 dev_err(&pdev
->dev
, "Error getting clock\n");
170 ret
= clk_prepare_enable(sdhci_pdata
->sys_clk
);
172 dev_err(&pdev
->dev
, "Error enabling clock\n");
176 sdhci_pdata
->base_clk
= devm_clk_get(&pdev
->dev
, "base_clk");
177 if (IS_ERR(sdhci_pdata
->base_clk
)) {
178 ret
= PTR_ERR(sdhci_pdata
->base_clk
);
179 dev_err(&pdev
->dev
, "Error getting clock\n");
183 ret
= clk_prepare_enable(sdhci_pdata
->base_clk
);
185 dev_err(&pdev
->dev
, "Error enabling clock\n");
189 ret
= mmc_of_parse(host
->mmc
);
193 pic32_sdhci_probe_platform(pdev
, sdhci_pdata
);
195 ret
= sdhci_add_host(host
);
199 dev_info(&pdev
->dev
, "Successfully added sdhci host\n");
203 clk_disable_unprepare(sdhci_pdata
->base_clk
);
205 clk_disable_unprepare(sdhci_pdata
->sys_clk
);
207 sdhci_pltfm_free(pdev
);
209 dev_err(&pdev
->dev
, "pic32-sdhci probe failed: %d\n", ret
);
213 static int pic32_sdhci_remove(struct platform_device
*pdev
)
215 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
216 struct pic32_sdhci_priv
*sdhci_pdata
= sdhci_priv(host
);
219 scratch
= readl(host
->ioaddr
+ SDHCI_INT_STATUS
);
220 sdhci_remove_host(host
, scratch
== (u32
)~0);
221 clk_disable_unprepare(sdhci_pdata
->base_clk
);
222 clk_disable_unprepare(sdhci_pdata
->sys_clk
);
223 sdhci_pltfm_free(pdev
);
228 static const struct of_device_id pic32_sdhci_id_table
[] = {
229 { .compatible
= "microchip,pic32mzda-sdhci" },
232 MODULE_DEVICE_TABLE(of
, pic32_sdhci_id_table
);
234 static struct platform_driver pic32_sdhci_driver
= {
236 .name
= "pic32-sdhci",
237 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
238 .of_match_table
= of_match_ptr(pic32_sdhci_id_table
),
240 .probe
= pic32_sdhci_probe
,
241 .remove
= pic32_sdhci_remove
,
244 module_platform_driver(pic32_sdhci_driver
);
246 MODULE_DESCRIPTION("Microchip PIC32 SDHCI driver");
247 MODULE_AUTHOR("Pistirica Sorin Andrei & Sandeep Sheriker");
248 MODULE_LICENSE("GPL v2");