2 * linux/drivers/mmc/host/sdhci_f_sdh30.c
4 * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
5 * Vincent Yang <vincent.yang@tw.fujitsu.com>
6 * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org>
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.
13 #include <linux/acpi.h>
14 #include <linux/err.h>
15 #include <linux/delay.h>
16 #include <linux/module.h>
18 #include <linux/property.h>
19 #include <linux/clk.h>
21 #include "sdhci-pltfm.h"
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
33 #define F_SDH30_TUNING_SETTING 0x108
34 #define F_SDH30_CMD_CHK_DIS 0x00010000
36 #define F_SDH30_IO_CONTROL2 0x114
37 #define F_SDH30_CRES_O_DN 0x00080000
38 #define F_SDH30_MSEL_O_1_8 0x00040000
40 #define F_SDH30_ESD_CONTROL 0x124
41 #define F_SDH30_EMMC_RST 0x00000002
42 #define F_SDH30_EMMC_HS200 0x01000000
44 #define F_SDH30_CMD_DAT_DELAY 0x200
46 #define F_SDH30_MIN_CLOCK 400000
48 struct f_sdhost_priv
{
49 struct clk
*clk_iface
;
53 bool enable_cmd_dat_delay
;
56 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host
*host
)
58 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
61 usleep_range(2500, 3000);
62 ctrl
= sdhci_readl(host
, F_SDH30_IO_CONTROL2
);
63 ctrl
|= F_SDH30_CRES_O_DN
;
64 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
65 ctrl
|= F_SDH30_MSEL_O_1_8
;
66 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
68 ctrl
&= ~F_SDH30_CRES_O_DN
;
69 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
70 usleep_range(2500, 3000);
72 if (priv
->vendor_hs200
) {
73 dev_info(priv
->dev
, "%s: setting hs200\n", __func__
);
74 ctrl
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
75 ctrl
|= priv
->vendor_hs200
;
76 sdhci_writel(host
, ctrl
, F_SDH30_ESD_CONTROL
);
79 ctrl
= sdhci_readl(host
, F_SDH30_TUNING_SETTING
);
80 ctrl
|= F_SDH30_CMD_CHK_DIS
;
81 sdhci_writel(host
, ctrl
, F_SDH30_TUNING_SETTING
);
84 static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host
*host
)
86 return F_SDH30_MIN_CLOCK
;
89 static void sdhci_f_sdh30_reset(struct sdhci_host
*host
, u8 mask
)
91 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
94 if (sdhci_readw(host
, SDHCI_CLOCK_CONTROL
) == 0)
95 sdhci_writew(host
, 0xBC01, SDHCI_CLOCK_CONTROL
);
97 sdhci_reset(host
, mask
);
99 if (priv
->enable_cmd_dat_delay
) {
100 ctl
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
101 ctl
|= F_SDH30_CMD_DAT_DELAY
;
102 sdhci_writel(host
, ctl
, F_SDH30_ESD_CONTROL
);
106 static const struct sdhci_ops sdhci_f_sdh30_ops
= {
107 .voltage_switch
= sdhci_f_sdh30_soft_voltage_switch
,
108 .get_min_clock
= sdhci_f_sdh30_get_min_clock
,
109 .reset
= sdhci_f_sdh30_reset
,
110 .set_clock
= sdhci_set_clock
,
111 .set_bus_width
= sdhci_set_bus_width
,
112 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
115 static int sdhci_f_sdh30_probe(struct platform_device
*pdev
)
117 struct sdhci_host
*host
;
118 struct device
*dev
= &pdev
->dev
;
119 struct resource
*res
;
120 int irq
, ctrl
= 0, ret
= 0;
121 struct f_sdhost_priv
*priv
;
124 irq
= platform_get_irq(pdev
, 0);
126 dev_err(dev
, "%s: no irq specified\n", __func__
);
130 host
= sdhci_alloc_host(dev
, sizeof(struct f_sdhost_priv
));
132 return PTR_ERR(host
);
134 priv
= sdhci_priv(host
);
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
;
142 priv
->enable_cmd_dat_delay
= device_property_read_bool(dev
,
143 "fujitsu,cmd-dat-delay-select");
145 ret
= mmc_of_parse(host
->mmc
);
149 platform_set_drvdata(pdev
, host
);
151 host
->hw_name
= "f_sdh30";
152 host
->ops
= &sdhci_f_sdh30_ops
;
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
);
162 if (dev_of_node(dev
)) {
163 sdhci_get_of_property(pdev
);
165 priv
->clk_iface
= devm_clk_get(&pdev
->dev
, "iface");
166 if (IS_ERR(priv
->clk_iface
)) {
167 ret
= PTR_ERR(priv
->clk_iface
);
171 ret
= clk_prepare_enable(priv
->clk_iface
);
175 priv
->clk
= devm_clk_get(&pdev
->dev
, "core");
176 if (IS_ERR(priv
->clk
)) {
177 ret
= PTR_ERR(priv
->clk
);
181 ret
= clk_prepare_enable(priv
->clk
);
186 /* init vendor specific regs */
187 ctrl
= sdhci_readw(host
, F_SDH30_AHB_CONFIG
);
188 ctrl
|= F_SDH30_SIN
| F_SDH30_AHB_INCR_16
| F_SDH30_AHB_INCR_8
|
190 ctrl
&= ~(F_SDH30_AHB_BIGED
| F_SDH30_BUSLOCK_EN
);
191 sdhci_writew(host
, ctrl
, F_SDH30_AHB_CONFIG
);
193 reg
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
194 sdhci_writel(host
, reg
& ~F_SDH30_EMMC_RST
, F_SDH30_ESD_CONTROL
);
196 sdhci_writel(host
, reg
| F_SDH30_EMMC_RST
, F_SDH30_ESD_CONTROL
);
198 reg
= sdhci_readl(host
, SDHCI_CAPABILITIES
);
199 if (reg
& SDHCI_CAN_DO_8BIT
)
200 priv
->vendor_hs200
= F_SDH30_EMMC_HS200
;
202 ret
= sdhci_add_host(host
);
209 clk_disable_unprepare(priv
->clk
);
211 clk_disable_unprepare(priv
->clk_iface
);
213 sdhci_free_host(host
);
217 static int sdhci_f_sdh30_remove(struct platform_device
*pdev
)
219 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
220 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
222 sdhci_remove_host(host
, readl(host
->ioaddr
+ SDHCI_INT_STATUS
) ==
225 clk_disable_unprepare(priv
->clk_iface
);
226 clk_disable_unprepare(priv
->clk
);
228 sdhci_free_host(host
);
229 platform_set_drvdata(pdev
, NULL
);
235 static const struct of_device_id f_sdh30_dt_ids
[] = {
236 { .compatible
= "fujitsu,mb86s70-sdhci-3.0" },
239 MODULE_DEVICE_TABLE(of
, f_sdh30_dt_ids
);
243 static const struct acpi_device_id f_sdh30_acpi_ids
[] = {
247 MODULE_DEVICE_TABLE(acpi
, f_sdh30_acpi_ids
);
250 static struct platform_driver sdhci_f_sdh30_driver
= {
253 .of_match_table
= of_match_ptr(f_sdh30_dt_ids
),
254 .acpi_match_table
= ACPI_PTR(f_sdh30_acpi_ids
),
255 .pm
= &sdhci_pltfm_pmops
,
257 .probe
= sdhci_f_sdh30_probe
,
258 .remove
= sdhci_f_sdh30_remove
,
261 module_platform_driver(sdhci_f_sdh30_driver
);
263 MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
264 MODULE_LICENSE("GPL v2");
265 MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
266 MODULE_ALIAS("platform:f_sdh30");