1 // SPDX-License-Identifier: GPL-2.0-only
3 * linux/drivers/mmc/host/sdhci_f_sdh30.c
5 * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
6 * Vincent Yang <vincent.yang@tw.fujitsu.com>
7 * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org>
10 #include <linux/acpi.h>
11 #include <linux/err.h>
12 #include <linux/delay.h>
13 #include <linux/module.h>
15 #include <linux/property.h>
16 #include <linux/clk.h>
18 #include "sdhci-pltfm.h"
19 #include "sdhci_f_sdh30.h"
21 struct f_sdhost_priv
{
22 struct clk
*clk_iface
;
26 bool enable_cmd_dat_delay
;
29 static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host
*host
)
31 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
34 usleep_range(2500, 3000);
35 ctrl
= sdhci_readl(host
, F_SDH30_IO_CONTROL2
);
36 ctrl
|= F_SDH30_CRES_O_DN
;
37 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
38 ctrl
|= F_SDH30_MSEL_O_1_8
;
39 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
41 ctrl
&= ~F_SDH30_CRES_O_DN
;
42 sdhci_writel(host
, ctrl
, F_SDH30_IO_CONTROL2
);
43 usleep_range(2500, 3000);
45 if (priv
->vendor_hs200
) {
46 dev_info(priv
->dev
, "%s: setting hs200\n", __func__
);
47 ctrl
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
48 ctrl
|= priv
->vendor_hs200
;
49 sdhci_writel(host
, ctrl
, F_SDH30_ESD_CONTROL
);
52 ctrl
= sdhci_readl(host
, F_SDH30_TUNING_SETTING
);
53 ctrl
|= F_SDH30_CMD_CHK_DIS
;
54 sdhci_writel(host
, ctrl
, F_SDH30_TUNING_SETTING
);
57 static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host
*host
)
59 return F_SDH30_MIN_CLOCK
;
62 static void sdhci_f_sdh30_reset(struct sdhci_host
*host
, u8 mask
)
64 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
67 if (sdhci_readw(host
, SDHCI_CLOCK_CONTROL
) == 0)
68 sdhci_writew(host
, 0xBC01, SDHCI_CLOCK_CONTROL
);
70 sdhci_reset(host
, mask
);
72 if (priv
->enable_cmd_dat_delay
) {
73 ctl
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
74 ctl
|= F_SDH30_CMD_DAT_DELAY
;
75 sdhci_writel(host
, ctl
, F_SDH30_ESD_CONTROL
);
79 static const struct sdhci_ops sdhci_f_sdh30_ops
= {
80 .voltage_switch
= sdhci_f_sdh30_soft_voltage_switch
,
81 .get_min_clock
= sdhci_f_sdh30_get_min_clock
,
82 .reset
= sdhci_f_sdh30_reset
,
83 .set_clock
= sdhci_set_clock
,
84 .set_bus_width
= sdhci_set_bus_width
,
85 .set_uhs_signaling
= sdhci_set_uhs_signaling
,
88 static int sdhci_f_sdh30_probe(struct platform_device
*pdev
)
90 struct sdhci_host
*host
;
91 struct device
*dev
= &pdev
->dev
;
92 int irq
, ctrl
= 0, ret
= 0;
93 struct f_sdhost_priv
*priv
;
96 irq
= platform_get_irq(pdev
, 0);
100 host
= sdhci_alloc_host(dev
, sizeof(struct f_sdhost_priv
));
102 return PTR_ERR(host
);
104 priv
= sdhci_priv(host
);
107 host
->quirks
= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
|
108 SDHCI_QUIRK_INVERTED_WRITE_PROTECT
;
109 host
->quirks2
= SDHCI_QUIRK2_SUPPORT_SINGLE
|
110 SDHCI_QUIRK2_TUNING_WORK_AROUND
;
112 priv
->enable_cmd_dat_delay
= device_property_read_bool(dev
,
113 "fujitsu,cmd-dat-delay-select");
115 ret
= mmc_of_parse(host
->mmc
);
119 platform_set_drvdata(pdev
, host
);
121 host
->hw_name
= "f_sdh30";
122 host
->ops
= &sdhci_f_sdh30_ops
;
125 host
->ioaddr
= devm_platform_ioremap_resource(pdev
, 0);
126 if (IS_ERR(host
->ioaddr
)) {
127 ret
= PTR_ERR(host
->ioaddr
);
131 if (dev_of_node(dev
)) {
132 sdhci_get_of_property(pdev
);
134 priv
->clk_iface
= devm_clk_get(&pdev
->dev
, "iface");
135 if (IS_ERR(priv
->clk_iface
)) {
136 ret
= PTR_ERR(priv
->clk_iface
);
140 ret
= clk_prepare_enable(priv
->clk_iface
);
144 priv
->clk
= devm_clk_get(&pdev
->dev
, "core");
145 if (IS_ERR(priv
->clk
)) {
146 ret
= PTR_ERR(priv
->clk
);
150 ret
= clk_prepare_enable(priv
->clk
);
155 /* init vendor specific regs */
156 ctrl
= sdhci_readw(host
, F_SDH30_AHB_CONFIG
);
157 ctrl
|= F_SDH30_SIN
| F_SDH30_AHB_INCR_16
| F_SDH30_AHB_INCR_8
|
159 ctrl
&= ~(F_SDH30_AHB_BIGED
| F_SDH30_BUSLOCK_EN
);
160 sdhci_writew(host
, ctrl
, F_SDH30_AHB_CONFIG
);
162 reg
= sdhci_readl(host
, F_SDH30_ESD_CONTROL
);
163 sdhci_writel(host
, reg
& ~F_SDH30_EMMC_RST
, F_SDH30_ESD_CONTROL
);
165 sdhci_writel(host
, reg
| F_SDH30_EMMC_RST
, F_SDH30_ESD_CONTROL
);
167 reg
= sdhci_readl(host
, SDHCI_CAPABILITIES
);
168 if (reg
& SDHCI_CAN_DO_8BIT
)
169 priv
->vendor_hs200
= F_SDH30_EMMC_HS200
;
171 ret
= sdhci_add_host(host
);
178 clk_disable_unprepare(priv
->clk
);
180 clk_disable_unprepare(priv
->clk_iface
);
182 sdhci_free_host(host
);
186 static int sdhci_f_sdh30_remove(struct platform_device
*pdev
)
188 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
189 struct f_sdhost_priv
*priv
= sdhci_priv(host
);
191 sdhci_remove_host(host
, readl(host
->ioaddr
+ SDHCI_INT_STATUS
) ==
194 clk_disable_unprepare(priv
->clk_iface
);
195 clk_disable_unprepare(priv
->clk
);
197 sdhci_free_host(host
);
198 platform_set_drvdata(pdev
, NULL
);
204 static const struct of_device_id f_sdh30_dt_ids
[] = {
205 { .compatible
= "fujitsu,mb86s70-sdhci-3.0" },
208 MODULE_DEVICE_TABLE(of
, f_sdh30_dt_ids
);
212 static const struct acpi_device_id f_sdh30_acpi_ids
[] = {
216 MODULE_DEVICE_TABLE(acpi
, f_sdh30_acpi_ids
);
219 static struct platform_driver sdhci_f_sdh30_driver
= {
222 .of_match_table
= of_match_ptr(f_sdh30_dt_ids
),
223 .acpi_match_table
= ACPI_PTR(f_sdh30_acpi_ids
),
224 .pm
= &sdhci_pltfm_pmops
,
226 .probe
= sdhci_f_sdh30_probe
,
227 .remove
= sdhci_f_sdh30_remove
,
230 module_platform_driver(sdhci_f_sdh30_driver
);
232 MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
233 MODULE_LICENSE("GPL v2");
234 MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
235 MODULE_ALIAS("platform:f_sdh30");