.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/drivers/mmc/host/sdhci_f_sdh30.c |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd |
---|
5 | 6 | * Vincent Yang <vincent.yang@tw.fujitsu.com> |
---|
6 | 7 | * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org> |
---|
7 | | - * |
---|
8 | | - * This program is free software: you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation, version 2 of the License. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/acpi.h> |
---|
.. | .. |
---|
19 | 16 | #include <linux/clk.h> |
---|
20 | 17 | |
---|
21 | 18 | #include "sdhci-pltfm.h" |
---|
22 | | - |
---|
23 | | -/* F_SDH30 extended Controller registers */ |
---|
24 | | -#define F_SDH30_AHB_CONFIG 0x100 |
---|
25 | | -#define F_SDH30_AHB_BIGED 0x00000040 |
---|
26 | | -#define F_SDH30_BUSLOCK_DMA 0x00000020 |
---|
27 | | -#define F_SDH30_BUSLOCK_EN 0x00000010 |
---|
28 | | -#define F_SDH30_SIN 0x00000008 |
---|
29 | | -#define F_SDH30_AHB_INCR_16 0x00000004 |
---|
30 | | -#define F_SDH30_AHB_INCR_8 0x00000002 |
---|
31 | | -#define F_SDH30_AHB_INCR_4 0x00000001 |
---|
32 | | - |
---|
33 | | -#define F_SDH30_TUNING_SETTING 0x108 |
---|
34 | | -#define F_SDH30_CMD_CHK_DIS 0x00010000 |
---|
35 | | - |
---|
36 | | -#define F_SDH30_IO_CONTROL2 0x114 |
---|
37 | | -#define F_SDH30_CRES_O_DN 0x00080000 |
---|
38 | | -#define F_SDH30_MSEL_O_1_8 0x00040000 |
---|
39 | | - |
---|
40 | | -#define F_SDH30_ESD_CONTROL 0x124 |
---|
41 | | -#define F_SDH30_EMMC_RST 0x00000002 |
---|
42 | | -#define F_SDH30_EMMC_HS200 0x01000000 |
---|
43 | | - |
---|
44 | | -#define F_SDH30_CMD_DAT_DELAY 0x200 |
---|
45 | | - |
---|
46 | | -#define F_SDH30_MIN_CLOCK 400000 |
---|
| 19 | +#include "sdhci_f_sdh30.h" |
---|
47 | 20 | |
---|
48 | 21 | struct f_sdhost_priv { |
---|
49 | 22 | struct clk *clk_iface; |
---|
.. | .. |
---|
53 | 26 | bool enable_cmd_dat_delay; |
---|
54 | 27 | }; |
---|
55 | 28 | |
---|
| 29 | +static void *sdhci_f_sdhost_priv(struct sdhci_host *host) |
---|
| 30 | +{ |
---|
| 31 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 32 | + |
---|
| 33 | + return sdhci_pltfm_priv(pltfm_host); |
---|
| 34 | +} |
---|
| 35 | + |
---|
56 | 36 | static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) |
---|
57 | 37 | { |
---|
58 | | - struct f_sdhost_priv *priv = sdhci_priv(host); |
---|
| 38 | + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); |
---|
59 | 39 | u32 ctrl = 0; |
---|
60 | 40 | |
---|
61 | 41 | usleep_range(2500, 3000); |
---|
.. | .. |
---|
88 | 68 | |
---|
89 | 69 | static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) |
---|
90 | 70 | { |
---|
91 | | - struct f_sdhost_priv *priv = sdhci_priv(host); |
---|
| 71 | + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); |
---|
92 | 72 | u32 ctl; |
---|
93 | 73 | |
---|
94 | 74 | if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) |
---|
.. | .. |
---|
112 | 92 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
---|
113 | 93 | }; |
---|
114 | 94 | |
---|
| 95 | +static const struct sdhci_pltfm_data sdhci_f_sdh30_pltfm_data = { |
---|
| 96 | + .ops = &sdhci_f_sdh30_ops, |
---|
| 97 | + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
---|
| 98 | + | SDHCI_QUIRK_INVERTED_WRITE_PROTECT, |
---|
| 99 | + .quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
---|
| 100 | + | SDHCI_QUIRK2_TUNING_WORK_AROUND, |
---|
| 101 | +}; |
---|
| 102 | + |
---|
115 | 103 | static int sdhci_f_sdh30_probe(struct platform_device *pdev) |
---|
116 | 104 | { |
---|
117 | 105 | struct sdhci_host *host; |
---|
118 | 106 | struct device *dev = &pdev->dev; |
---|
119 | | - struct resource *res; |
---|
120 | | - int irq, ctrl = 0, ret = 0; |
---|
| 107 | + int ctrl = 0, ret = 0; |
---|
121 | 108 | struct f_sdhost_priv *priv; |
---|
| 109 | + struct sdhci_pltfm_host *pltfm_host; |
---|
122 | 110 | u32 reg = 0; |
---|
123 | 111 | |
---|
124 | | - irq = platform_get_irq(pdev, 0); |
---|
125 | | - if (irq < 0) { |
---|
126 | | - dev_err(dev, "%s: no irq specified\n", __func__); |
---|
127 | | - return irq; |
---|
128 | | - } |
---|
129 | | - |
---|
130 | | - host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv)); |
---|
| 112 | + host = sdhci_pltfm_init(pdev, &sdhci_f_sdh30_pltfm_data, |
---|
| 113 | + sizeof(struct f_sdhost_priv)); |
---|
131 | 114 | if (IS_ERR(host)) |
---|
132 | 115 | return PTR_ERR(host); |
---|
133 | 116 | |
---|
134 | | - priv = sdhci_priv(host); |
---|
| 117 | + pltfm_host = sdhci_priv(host); |
---|
| 118 | + priv = sdhci_pltfm_priv(pltfm_host); |
---|
135 | 119 | priv->dev = dev; |
---|
136 | | - |
---|
137 | | - host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | |
---|
138 | | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT; |
---|
139 | | - host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | |
---|
140 | | - SDHCI_QUIRK2_TUNING_WORK_AROUND; |
---|
141 | 120 | |
---|
142 | 121 | priv->enable_cmd_dat_delay = device_property_read_bool(dev, |
---|
143 | 122 | "fujitsu,cmd-dat-delay-select"); |
---|
.. | .. |
---|
145 | 124 | ret = mmc_of_parse(host->mmc); |
---|
146 | 125 | if (ret) |
---|
147 | 126 | goto err; |
---|
148 | | - |
---|
149 | | - platform_set_drvdata(pdev, host); |
---|
150 | | - |
---|
151 | | - host->hw_name = "f_sdh30"; |
---|
152 | | - host->ops = &sdhci_f_sdh30_ops; |
---|
153 | | - host->irq = irq; |
---|
154 | | - |
---|
155 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
156 | | - host->ioaddr = devm_ioremap_resource(&pdev->dev, res); |
---|
157 | | - if (IS_ERR(host->ioaddr)) { |
---|
158 | | - ret = PTR_ERR(host->ioaddr); |
---|
159 | | - goto err; |
---|
160 | | - } |
---|
161 | 127 | |
---|
162 | 128 | if (dev_of_node(dev)) { |
---|
163 | 129 | sdhci_get_of_property(pdev); |
---|
.. | .. |
---|
199 | 165 | if (reg & SDHCI_CAN_DO_8BIT) |
---|
200 | 166 | priv->vendor_hs200 = F_SDH30_EMMC_HS200; |
---|
201 | 167 | |
---|
| 168 | + if (!(reg & SDHCI_TIMEOUT_CLK_MASK)) |
---|
| 169 | + host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; |
---|
| 170 | + |
---|
202 | 171 | ret = sdhci_add_host(host); |
---|
203 | 172 | if (ret) |
---|
204 | 173 | goto err_add_host; |
---|
.. | .. |
---|
210 | 179 | err_clk: |
---|
211 | 180 | clk_disable_unprepare(priv->clk_iface); |
---|
212 | 181 | err: |
---|
213 | | - sdhci_free_host(host); |
---|
| 182 | + sdhci_pltfm_free(pdev); |
---|
| 183 | + |
---|
214 | 184 | return ret; |
---|
215 | 185 | } |
---|
216 | 186 | |
---|
217 | 187 | static int sdhci_f_sdh30_remove(struct platform_device *pdev) |
---|
218 | 188 | { |
---|
219 | 189 | struct sdhci_host *host = platform_get_drvdata(pdev); |
---|
220 | | - struct f_sdhost_priv *priv = sdhci_priv(host); |
---|
| 190 | + struct f_sdhost_priv *priv = sdhci_f_sdhost_priv(host); |
---|
| 191 | + struct clk *clk_iface = priv->clk_iface; |
---|
| 192 | + struct clk *clk = priv->clk; |
---|
221 | 193 | |
---|
222 | | - sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == |
---|
223 | | - 0xffffffff); |
---|
| 194 | + sdhci_pltfm_unregister(pdev); |
---|
224 | 195 | |
---|
225 | | - clk_disable_unprepare(priv->clk_iface); |
---|
226 | | - clk_disable_unprepare(priv->clk); |
---|
227 | | - |
---|
228 | | - sdhci_free_host(host); |
---|
229 | | - platform_set_drvdata(pdev, NULL); |
---|
| 196 | + clk_disable_unprepare(clk_iface); |
---|
| 197 | + clk_disable_unprepare(clk); |
---|
230 | 198 | |
---|
231 | 199 | return 0; |
---|
232 | 200 | } |
---|