1dd79b7e3STakao Orito // SPDX-License-Identifier: GPL-2.0
2dd79b7e3STakao Orito /*
3dd79b7e3STakao Orito * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
4dd79b7e3STakao Orito * Vincent Yang <vincent.yang@tw.fujitsu.com>
5dd79b7e3STakao Orito * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org>
6dd79b7e3STakao Orito * Copyright (C) 2019 Socionext Inc.
7dd79b7e3STakao Orito * Takao Orito <orito.takao@socionext.com>
8dd79b7e3STakao Orito */
9dd79b7e3STakao Orito
10dd79b7e3STakao Orito #include <linux/bits.h>
11dd79b7e3STakao Orito #include <linux/clk.h>
12dd79b7e3STakao Orito #include <linux/delay.h>
13dd79b7e3STakao Orito #include <linux/err.h>
14dd79b7e3STakao Orito #include <linux/gpio/consumer.h>
15dd79b7e3STakao Orito #include <linux/module.h>
16dd79b7e3STakao Orito #include <linux/of.h>
17dd79b7e3STakao Orito #include <linux/property.h>
18dd79b7e3STakao Orito
19dd79b7e3STakao Orito #include "sdhci-pltfm.h"
20dd79b7e3STakao Orito #include "sdhci_f_sdh30.h"
21dd79b7e3STakao Orito
22dd79b7e3STakao Orito /* milbeaut bridge controller register */
23dd79b7e3STakao Orito #define MLB_SOFT_RESET 0x0200
24dd79b7e3STakao Orito #define MLB_SOFT_RESET_RSTX BIT(0)
25dd79b7e3STakao Orito
26dd79b7e3STakao Orito #define MLB_WP_CD_LED_SET 0x0210
27dd79b7e3STakao Orito #define MLB_WP_CD_LED_SET_LED_INV BIT(2)
28dd79b7e3STakao Orito
29dd79b7e3STakao Orito #define MLB_CR_SET 0x0220
30dd79b7e3STakao Orito #define MLB_CR_SET_CR_TOCLKUNIT BIT(24)
31dd79b7e3STakao Orito #define MLB_CR_SET_CR_TOCLKFREQ_SFT (16)
32dd79b7e3STakao Orito #define MLB_CR_SET_CR_TOCLKFREQ_MASK (0x3F << MLB_CR_SET_CR_TOCLKFREQ_SFT)
33dd79b7e3STakao Orito #define MLB_CR_SET_CR_BCLKFREQ_SFT (8)
34dd79b7e3STakao Orito #define MLB_CR_SET_CR_BCLKFREQ_MASK (0xFF << MLB_CR_SET_CR_BCLKFREQ_SFT)
35dd79b7e3STakao Orito #define MLB_CR_SET_CR_RTUNTIMER_SFT (4)
36dd79b7e3STakao Orito #define MLB_CR_SET_CR_RTUNTIMER_MASK (0xF << MLB_CR_SET_CR_RTUNTIMER_SFT)
37dd79b7e3STakao Orito
38dd79b7e3STakao Orito #define MLB_SD_TOCLK_I_DIV 16
39dd79b7e3STakao Orito #define MLB_TOCLKFREQ_UNIT_THRES 16000000
40dd79b7e3STakao Orito #define MLB_CAL_TOCLKFREQ_MHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000000)
41dd79b7e3STakao Orito #define MLB_CAL_TOCLKFREQ_KHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000)
42dd79b7e3STakao Orito #define MLB_TOCLKFREQ_MAX 63
43dd79b7e3STakao Orito #define MLB_TOCLKFREQ_MIN 1
44dd79b7e3STakao Orito
45dd79b7e3STakao Orito #define MLB_SD_BCLK_I_DIV 4
46dd79b7e3STakao Orito #define MLB_CAL_BCLKFREQ(rate) (rate / MLB_SD_BCLK_I_DIV / 1000000)
47dd79b7e3STakao Orito #define MLB_BCLKFREQ_MAX 255
48dd79b7e3STakao Orito #define MLB_BCLKFREQ_MIN 1
49dd79b7e3STakao Orito
50dd79b7e3STakao Orito #define MLB_CDR_SET 0x0230
51dd79b7e3STakao Orito #define MLB_CDR_SET_CLK2POW16 3
52dd79b7e3STakao Orito
53dd79b7e3STakao Orito struct f_sdhost_priv {
54dd79b7e3STakao Orito struct clk *clk_iface;
55dd79b7e3STakao Orito struct clk *clk;
56dd79b7e3STakao Orito struct device *dev;
57dd79b7e3STakao Orito bool enable_cmd_dat_delay;
58dd79b7e3STakao Orito };
59dd79b7e3STakao Orito
sdhci_milbeaut_soft_voltage_switch(struct sdhci_host * host)60dd79b7e3STakao Orito static void sdhci_milbeaut_soft_voltage_switch(struct sdhci_host *host)
61dd79b7e3STakao Orito {
62dd79b7e3STakao Orito u32 ctrl = 0;
63dd79b7e3STakao Orito
64dd79b7e3STakao Orito usleep_range(2500, 3000);
65dd79b7e3STakao Orito ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
66dd79b7e3STakao Orito ctrl |= F_SDH30_CRES_O_DN;
67dd79b7e3STakao Orito sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
68dd79b7e3STakao Orito ctrl |= F_SDH30_MSEL_O_1_8;
69dd79b7e3STakao Orito sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
70dd79b7e3STakao Orito
71dd79b7e3STakao Orito ctrl &= ~F_SDH30_CRES_O_DN;
72dd79b7e3STakao Orito sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
73dd79b7e3STakao Orito usleep_range(2500, 3000);
74dd79b7e3STakao Orito
75dd79b7e3STakao Orito ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
76dd79b7e3STakao Orito ctrl |= F_SDH30_CMD_CHK_DIS;
77dd79b7e3STakao Orito sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
78dd79b7e3STakao Orito }
79dd79b7e3STakao Orito
sdhci_milbeaut_get_min_clock(struct sdhci_host * host)80dd79b7e3STakao Orito static unsigned int sdhci_milbeaut_get_min_clock(struct sdhci_host *host)
81dd79b7e3STakao Orito {
82dd79b7e3STakao Orito return F_SDH30_MIN_CLOCK;
83dd79b7e3STakao Orito }
84dd79b7e3STakao Orito
sdhci_milbeaut_reset(struct sdhci_host * host,u8 mask)85dd79b7e3STakao Orito static void sdhci_milbeaut_reset(struct sdhci_host *host, u8 mask)
86dd79b7e3STakao Orito {
87dd79b7e3STakao Orito struct f_sdhost_priv *priv = sdhci_priv(host);
88dd79b7e3STakao Orito u16 clk;
89dd79b7e3STakao Orito u32 ctl;
90dd79b7e3STakao Orito ktime_t timeout;
91dd79b7e3STakao Orito
92dd79b7e3STakao Orito clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
93dd79b7e3STakao Orito clk = (clk & ~SDHCI_CLOCK_CARD_EN) | SDHCI_CLOCK_INT_EN;
94dd79b7e3STakao Orito sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
95dd79b7e3STakao Orito
96dd79b7e3STakao Orito sdhci_reset(host, mask);
97dd79b7e3STakao Orito
98dd79b7e3STakao Orito clk |= SDHCI_CLOCK_CARD_EN;
99dd79b7e3STakao Orito sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
100dd79b7e3STakao Orito
101dd79b7e3STakao Orito timeout = ktime_add_ms(ktime_get(), 10);
102dd79b7e3STakao Orito while (1) {
103dd79b7e3STakao Orito bool timedout = ktime_after(ktime_get(), timeout);
104dd79b7e3STakao Orito
105dd79b7e3STakao Orito clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
106dd79b7e3STakao Orito if (clk & SDHCI_CLOCK_INT_STABLE)
107dd79b7e3STakao Orito break;
108dd79b7e3STakao Orito if (timedout) {
109dd79b7e3STakao Orito pr_err("%s: Internal clock never stabilised.\n",
110dd79b7e3STakao Orito mmc_hostname(host->mmc));
111dd79b7e3STakao Orito sdhci_dumpregs(host);
112dd79b7e3STakao Orito return;
113dd79b7e3STakao Orito }
114dd79b7e3STakao Orito udelay(10);
115dd79b7e3STakao Orito }
116dd79b7e3STakao Orito
117dd79b7e3STakao Orito if (priv->enable_cmd_dat_delay) {
118dd79b7e3STakao Orito ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
119dd79b7e3STakao Orito ctl |= F_SDH30_CMD_DAT_DELAY;
120dd79b7e3STakao Orito sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
121dd79b7e3STakao Orito }
122dd79b7e3STakao Orito }
123dd79b7e3STakao Orito
124dd79b7e3STakao Orito static const struct sdhci_ops sdhci_milbeaut_ops = {
125dd79b7e3STakao Orito .voltage_switch = sdhci_milbeaut_soft_voltage_switch,
126dd79b7e3STakao Orito .get_min_clock = sdhci_milbeaut_get_min_clock,
127dd79b7e3STakao Orito .reset = sdhci_milbeaut_reset,
128dd79b7e3STakao Orito .set_clock = sdhci_set_clock,
129dd79b7e3STakao Orito .set_bus_width = sdhci_set_bus_width,
130dd79b7e3STakao Orito .set_uhs_signaling = sdhci_set_uhs_signaling,
131d2abc6e2SNicolas Saenz Julienne .set_power = sdhci_set_power_and_bus_voltage,
132dd79b7e3STakao Orito };
133dd79b7e3STakao Orito
sdhci_milbeaut_bridge_reset(struct sdhci_host * host,int reset_flag)134dd79b7e3STakao Orito static void sdhci_milbeaut_bridge_reset(struct sdhci_host *host,
135dd79b7e3STakao Orito int reset_flag)
136dd79b7e3STakao Orito {
137dd79b7e3STakao Orito if (reset_flag)
138dd79b7e3STakao Orito sdhci_writel(host, 0, MLB_SOFT_RESET);
139dd79b7e3STakao Orito else
140dd79b7e3STakao Orito sdhci_writel(host, MLB_SOFT_RESET_RSTX, MLB_SOFT_RESET);
141dd79b7e3STakao Orito }
142dd79b7e3STakao Orito
sdhci_milbeaut_bridge_init(struct sdhci_host * host,int rate)143dd79b7e3STakao Orito static void sdhci_milbeaut_bridge_init(struct sdhci_host *host,
144dd79b7e3STakao Orito int rate)
145dd79b7e3STakao Orito {
146dd79b7e3STakao Orito u32 val, clk;
147dd79b7e3STakao Orito
148dd79b7e3STakao Orito /* IO_SDIO_CR_SET should be set while reset */
149dd79b7e3STakao Orito val = sdhci_readl(host, MLB_CR_SET);
150dd79b7e3STakao Orito val &= ~(MLB_CR_SET_CR_TOCLKFREQ_MASK | MLB_CR_SET_CR_TOCLKUNIT |
151dd79b7e3STakao Orito MLB_CR_SET_CR_BCLKFREQ_MASK);
152dd79b7e3STakao Orito if (rate >= MLB_TOCLKFREQ_UNIT_THRES) {
153dd79b7e3STakao Orito clk = MLB_CAL_TOCLKFREQ_MHZ(rate);
154dd79b7e3STakao Orito clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
155dd79b7e3STakao Orito val |= MLB_CR_SET_CR_TOCLKUNIT |
156dd79b7e3STakao Orito (clk << MLB_CR_SET_CR_TOCLKFREQ_SFT);
157dd79b7e3STakao Orito } else {
158dd79b7e3STakao Orito clk = MLB_CAL_TOCLKFREQ_KHZ(rate);
159dd79b7e3STakao Orito clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
160dd79b7e3STakao Orito clk = max_t(u32, MLB_TOCLKFREQ_MIN, clk);
161dd79b7e3STakao Orito val |= clk << MLB_CR_SET_CR_TOCLKFREQ_SFT;
162dd79b7e3STakao Orito }
163dd79b7e3STakao Orito
164dd79b7e3STakao Orito clk = MLB_CAL_BCLKFREQ(rate);
165dd79b7e3STakao Orito clk = min_t(u32, MLB_BCLKFREQ_MAX, clk);
166dd79b7e3STakao Orito clk = max_t(u32, MLB_BCLKFREQ_MIN, clk);
167dd79b7e3STakao Orito val |= clk << MLB_CR_SET_CR_BCLKFREQ_SFT;
168dd79b7e3STakao Orito val &= ~MLB_CR_SET_CR_RTUNTIMER_MASK;
169dd79b7e3STakao Orito sdhci_writel(host, val, MLB_CR_SET);
170dd79b7e3STakao Orito
171dd79b7e3STakao Orito sdhci_writel(host, MLB_CDR_SET_CLK2POW16, MLB_CDR_SET);
172dd79b7e3STakao Orito
173dd79b7e3STakao Orito sdhci_writel(host, MLB_WP_CD_LED_SET_LED_INV, MLB_WP_CD_LED_SET);
174dd79b7e3STakao Orito }
175dd79b7e3STakao Orito
sdhci_milbeaut_vendor_init(struct sdhci_host * host)176dd79b7e3STakao Orito static void sdhci_milbeaut_vendor_init(struct sdhci_host *host)
177dd79b7e3STakao Orito {
178dd79b7e3STakao Orito struct f_sdhost_priv *priv = sdhci_priv(host);
179dd79b7e3STakao Orito u32 ctl;
180dd79b7e3STakao Orito
181dd79b7e3STakao Orito ctl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
182dd79b7e3STakao Orito ctl |= F_SDH30_CRES_O_DN;
183dd79b7e3STakao Orito sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
184dd79b7e3STakao Orito ctl &= ~F_SDH30_MSEL_O_1_8;
185dd79b7e3STakao Orito sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
186dd79b7e3STakao Orito ctl &= ~F_SDH30_CRES_O_DN;
187dd79b7e3STakao Orito sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
188dd79b7e3STakao Orito
189dd79b7e3STakao Orito ctl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
190dd79b7e3STakao Orito ctl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
191dd79b7e3STakao Orito F_SDH30_AHB_INCR_4;
192dd79b7e3STakao Orito ctl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
193dd79b7e3STakao Orito sdhci_writew(host, ctl, F_SDH30_AHB_CONFIG);
194dd79b7e3STakao Orito
195dd79b7e3STakao Orito if (priv->enable_cmd_dat_delay) {
196dd79b7e3STakao Orito ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
197dd79b7e3STakao Orito ctl |= F_SDH30_CMD_DAT_DELAY;
198dd79b7e3STakao Orito sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
199dd79b7e3STakao Orito }
200dd79b7e3STakao Orito }
201dd79b7e3STakao Orito
202dd79b7e3STakao Orito static const struct of_device_id mlb_dt_ids[] = {
203dd79b7e3STakao Orito {
204dd79b7e3STakao Orito .compatible = "socionext,milbeaut-m10v-sdhci-3.0",
205dd79b7e3STakao Orito },
206dd79b7e3STakao Orito { /* sentinel */ }
207dd79b7e3STakao Orito };
208dd79b7e3STakao Orito MODULE_DEVICE_TABLE(of, mlb_dt_ids);
209dd79b7e3STakao Orito
sdhci_milbeaut_init(struct sdhci_host * host)210dd79b7e3STakao Orito static void sdhci_milbeaut_init(struct sdhci_host *host)
211dd79b7e3STakao Orito {
212dd79b7e3STakao Orito struct f_sdhost_priv *priv = sdhci_priv(host);
213dd79b7e3STakao Orito int rate = clk_get_rate(priv->clk);
214dd79b7e3STakao Orito u16 ctl;
215dd79b7e3STakao Orito
216dd79b7e3STakao Orito sdhci_milbeaut_bridge_reset(host, 0);
217dd79b7e3STakao Orito
218dd79b7e3STakao Orito ctl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
219dd79b7e3STakao Orito ctl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
220dd79b7e3STakao Orito sdhci_writew(host, ctl, SDHCI_CLOCK_CONTROL);
221dd79b7e3STakao Orito
222dd79b7e3STakao Orito sdhci_milbeaut_bridge_reset(host, 1);
223dd79b7e3STakao Orito
224dd79b7e3STakao Orito sdhci_milbeaut_bridge_init(host, rate);
225dd79b7e3STakao Orito sdhci_milbeaut_bridge_reset(host, 0);
226dd79b7e3STakao Orito
227dd79b7e3STakao Orito sdhci_milbeaut_vendor_init(host);
228dd79b7e3STakao Orito }
229dd79b7e3STakao Orito
sdhci_milbeaut_probe(struct platform_device * pdev)230dd79b7e3STakao Orito static int sdhci_milbeaut_probe(struct platform_device *pdev)
231dd79b7e3STakao Orito {
232dd79b7e3STakao Orito struct sdhci_host *host;
233dd79b7e3STakao Orito struct device *dev = &pdev->dev;
234dd79b7e3STakao Orito int irq, ret = 0;
235dd79b7e3STakao Orito struct f_sdhost_priv *priv;
236dd79b7e3STakao Orito
237dd79b7e3STakao Orito irq = platform_get_irq(pdev, 0);
238557c0315SYueHaibing if (irq < 0)
239dd79b7e3STakao Orito return irq;
240dd79b7e3STakao Orito
241dd79b7e3STakao Orito host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
242dd79b7e3STakao Orito if (IS_ERR(host))
243dd79b7e3STakao Orito return PTR_ERR(host);
244dd79b7e3STakao Orito
245dd79b7e3STakao Orito priv = sdhci_priv(host);
246dd79b7e3STakao Orito priv->dev = dev;
247dd79b7e3STakao Orito
248dd79b7e3STakao Orito host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
249dd79b7e3STakao Orito SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
250dd79b7e3STakao Orito SDHCI_QUIRK_CLOCK_BEFORE_RESET |
251dd79b7e3STakao Orito SDHCI_QUIRK_DELAY_AFTER_POWER;
252dd79b7e3STakao Orito host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
253dd79b7e3STakao Orito SDHCI_QUIRK2_TUNING_WORK_AROUND |
254dd79b7e3STakao Orito SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
255dd79b7e3STakao Orito
256dd79b7e3STakao Orito priv->enable_cmd_dat_delay = device_property_read_bool(dev,
257dd79b7e3STakao Orito "fujitsu,cmd-dat-delay-select");
258dd79b7e3STakao Orito
259dd79b7e3STakao Orito ret = mmc_of_parse(host->mmc);
260dd79b7e3STakao Orito if (ret)
261dd79b7e3STakao Orito goto err;
262dd79b7e3STakao Orito
263dd79b7e3STakao Orito platform_set_drvdata(pdev, host);
264dd79b7e3STakao Orito
265dd79b7e3STakao Orito host->hw_name = "f_sdh30";
266dd79b7e3STakao Orito host->ops = &sdhci_milbeaut_ops;
267dd79b7e3STakao Orito host->irq = irq;
268dd79b7e3STakao Orito
26975f6eacdSYangtao Li host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
270dd79b7e3STakao Orito if (IS_ERR(host->ioaddr)) {
271dd79b7e3STakao Orito ret = PTR_ERR(host->ioaddr);
272dd79b7e3STakao Orito goto err;
273dd79b7e3STakao Orito }
274dd79b7e3STakao Orito
275dd79b7e3STakao Orito if (dev_of_node(dev)) {
276dd79b7e3STakao Orito sdhci_get_of_property(pdev);
277dd79b7e3STakao Orito
278dd79b7e3STakao Orito priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
279dd79b7e3STakao Orito if (IS_ERR(priv->clk_iface)) {
280dd79b7e3STakao Orito ret = PTR_ERR(priv->clk_iface);
281dd79b7e3STakao Orito goto err;
282dd79b7e3STakao Orito }
283dd79b7e3STakao Orito
284dd79b7e3STakao Orito ret = clk_prepare_enable(priv->clk_iface);
285dd79b7e3STakao Orito if (ret)
286dd79b7e3STakao Orito goto err;
287dd79b7e3STakao Orito
288dd79b7e3STakao Orito priv->clk = devm_clk_get(&pdev->dev, "core");
289dd79b7e3STakao Orito if (IS_ERR(priv->clk)) {
290dd79b7e3STakao Orito ret = PTR_ERR(priv->clk);
291dd79b7e3STakao Orito goto err_clk;
292dd79b7e3STakao Orito }
293dd79b7e3STakao Orito
294dd79b7e3STakao Orito ret = clk_prepare_enable(priv->clk);
295dd79b7e3STakao Orito if (ret)
296dd79b7e3STakao Orito goto err_clk;
297dd79b7e3STakao Orito }
298dd79b7e3STakao Orito
299dd79b7e3STakao Orito sdhci_milbeaut_init(host);
300dd79b7e3STakao Orito
301dd79b7e3STakao Orito ret = sdhci_add_host(host);
302dd79b7e3STakao Orito if (ret)
303dd79b7e3STakao Orito goto err_add_host;
304dd79b7e3STakao Orito
305dd79b7e3STakao Orito return 0;
306dd79b7e3STakao Orito
307dd79b7e3STakao Orito err_add_host:
308dd79b7e3STakao Orito clk_disable_unprepare(priv->clk);
309dd79b7e3STakao Orito err_clk:
310dd79b7e3STakao Orito clk_disable_unprepare(priv->clk_iface);
311dd79b7e3STakao Orito err:
312dd79b7e3STakao Orito sdhci_free_host(host);
313dd79b7e3STakao Orito return ret;
314dd79b7e3STakao Orito }
315dd79b7e3STakao Orito
sdhci_milbeaut_remove(struct platform_device * pdev)316*9479a631SYangtao Li static void sdhci_milbeaut_remove(struct platform_device *pdev)
317dd79b7e3STakao Orito {
318dd79b7e3STakao Orito struct sdhci_host *host = platform_get_drvdata(pdev);
319dd79b7e3STakao Orito struct f_sdhost_priv *priv = sdhci_priv(host);
320dd79b7e3STakao Orito
321dd79b7e3STakao Orito sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
322dd79b7e3STakao Orito 0xffffffff);
323dd79b7e3STakao Orito
324dd79b7e3STakao Orito clk_disable_unprepare(priv->clk_iface);
325dd79b7e3STakao Orito clk_disable_unprepare(priv->clk);
326dd79b7e3STakao Orito
327dd79b7e3STakao Orito sdhci_free_host(host);
328dd79b7e3STakao Orito platform_set_drvdata(pdev, NULL);
329dd79b7e3STakao Orito }
330dd79b7e3STakao Orito
331dd79b7e3STakao Orito static struct platform_driver sdhci_milbeaut_driver = {
332dd79b7e3STakao Orito .driver = {
333dd79b7e3STakao Orito .name = "sdhci-milbeaut",
33431ae4035SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS,
3358069a60aSZhu Wang .of_match_table = mlb_dt_ids,
336dd79b7e3STakao Orito },
337dd79b7e3STakao Orito .probe = sdhci_milbeaut_probe,
338*9479a631SYangtao Li .remove_new = sdhci_milbeaut_remove,
339dd79b7e3STakao Orito };
340dd79b7e3STakao Orito
341dd79b7e3STakao Orito module_platform_driver(sdhci_milbeaut_driver);
342dd79b7e3STakao Orito
343dd79b7e3STakao Orito MODULE_DESCRIPTION("MILBEAUT SD Card Controller driver");
344dd79b7e3STakao Orito MODULE_AUTHOR("Takao Orito <orito.takao@socionext.com>");
345dd79b7e3STakao Orito MODULE_LICENSE("GPL v2");
346dd79b7e3STakao Orito MODULE_ALIAS("platform:sdhci-milbeaut");
347