Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with
  4 * integrated phy.
  5 *
  6 * Copyright (C) 2017 Arasan Chip Systems Inc.
  7 *
  8 * Author: Atul Garg <agarg@arasan.com>
  9 */
 10
 11#include <linux/pci.h>
 12#include <linux/delay.h>
 13
 14#include "sdhci.h"
 15#include "sdhci-pci.h"
 16
 17/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */
 18#define PHY_ADDR_REG	0x300
 19#define PHY_DAT_REG	0x304
 20
 21#define PHY_WRITE	BIT(8)
 22#define PHY_BUSY	BIT(9)
 23#define DATA_MASK	0xFF
 24
 25/* PHY Specific Registers */
 26#define DLL_STATUS	0x00
 27#define IPAD_CTRL1	0x01
 28#define IPAD_CTRL2	0x02
 29#define IPAD_STS	0x03
 30#define IOREN_CTRL1	0x06
 31#define IOREN_CTRL2	0x07
 32#define IOPU_CTRL1	0x08
 33#define IOPU_CTRL2	0x09
 34#define ITAP_DELAY	0x0C
 35#define OTAP_DELAY	0x0D
 36#define STRB_SEL	0x0E
 37#define CLKBUF_SEL	0x0F
 38#define MODE_CTRL	0x11
 39#define DLL_TRIM	0x12
 40#define CMD_CTRL	0x20
 41#define DATA_CTRL	0x21
 42#define STRB_CTRL	0x22
 43#define CLK_CTRL	0x23
 44#define PHY_CTRL	0x24
 45
 46#define DLL_ENBL	BIT(3)
 47#define RTRIM_EN	BIT(1)
 48#define PDB_ENBL	BIT(1)
 49#define RETB_ENBL	BIT(6)
 50#define ODEN_CMD	BIT(1)
 51#define ODEN_DAT	0xFF
 52#define REN_STRB	BIT(0)
 53#define REN_CMND	BIT(1)
 54#define REN_DATA	0xFF
 55#define PU_CMD		BIT(1)
 56#define PU_DAT		0xFF
 57#define ITAPDLY_EN	BIT(0)
 58#define OTAPDLY_EN	BIT(0)
 59#define OD_REL_CMD	BIT(1)
 60#define OD_REL_DAT	0xFF
 61#define DLLTRM_ICP	0x8
 62#define PDB_CMND	BIT(0)
 63#define PDB_DATA	0xFF
 64#define PDB_STRB	BIT(0)
 65#define PDB_CLOCK	BIT(0)
 66#define CALDONE_MASK	0x10
 67#define DLL_RDY_MASK	0x10
 68#define MAX_CLK_BUF	0x7
 69
 70/* Mode Controls */
 71#define ENHSTRB_MODE	BIT(0)
 72#define HS400_MODE	BIT(1)
 73#define LEGACY_MODE	BIT(2)
 74#define DDR50_MODE	BIT(3)
 75
 76/*
 77 * Controller has no specific bits for HS200/HS.
 78 * Used BIT(4), BIT(5) for software programming.
 79 */
 80#define HS200_MODE	BIT(4)
 81#define HISPD_MODE	BIT(5)
 82
 83#define OTAPDLY(x)	(((x) << 1) | OTAPDLY_EN)
 84#define ITAPDLY(x)	(((x) << 1) | ITAPDLY_EN)
 85#define FREQSEL(x)	(((x) << 5) | DLL_ENBL)
 86#define IOPAD(x, y)	((x) | ((y) << 2))
 87
 88/* Arasan private data */
 89struct arasan_host {
 90	u32 chg_clk;
 91};
 92
 93static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask)
 94{
 95	ktime_t timeout = ktime_add_us(ktime_get(), 100);
 96	bool failed;
 97	u8 val = 0;
 98
 99	while (1) {
100		failed = ktime_after(ktime_get(), timeout);
101		val = sdhci_readw(host, PHY_ADDR_REG);
102		if (!(val & mask))
103			return 0;
104		if (failed)
105			return -EBUSY;
106	}
107}
108
109static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset)
110{
111	sdhci_writew(host, data, PHY_DAT_REG);
112	sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG);
113	return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
114}
115
116static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data)
117{
118	int ret;
119
120	sdhci_writew(host, 0, PHY_DAT_REG);
121	sdhci_writew(host, offset, PHY_ADDR_REG);
122	ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
123
124	/* Masking valid data bits */
125	*data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK;
126	return ret;
127}
128
129static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask)
130{
131	int ret;
132	ktime_t timeout = ktime_add_us(ktime_get(), 100);
133	bool failed;
134	u8 val = 0;
135
136	while (1) {
137		failed = ktime_after(ktime_get(), timeout);
138		ret = arasan_phy_read(host, offset, &val);
139		if (ret)
140			return -EBUSY;
141		else if (val & mask)
142			return 0;
143		if (failed)
144			return -EBUSY;
145	}
146}
147
148/* Initialize the Arasan PHY */
149static int arasan_phy_init(struct sdhci_host *host)
150{
151	int ret;
152	u8 val;
153
154	/* Program IOPADs and wait for calibration to be done */
155	if (arasan_phy_read(host, IPAD_CTRL1, &val) ||
156	    arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) ||
157	    arasan_phy_read(host, IPAD_CTRL2, &val) ||
158	    arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2))
159		return -EBUSY;
160	ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK);
161	if (ret)
162		return -EBUSY;
163
164	/* Program CMD/Data lines */
165	if (arasan_phy_read(host, IOREN_CTRL1, &val) ||
166	    arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) ||
167	    arasan_phy_read(host, IOPU_CTRL1, &val) ||
168	    arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) ||
169	    arasan_phy_read(host, CMD_CTRL, &val) ||
170	    arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) ||
171	    arasan_phy_read(host, IOREN_CTRL2, &val) ||
172	    arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) ||
173	    arasan_phy_read(host, IOPU_CTRL2, &val) ||
174	    arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) ||
175	    arasan_phy_read(host, DATA_CTRL, &val) ||
176	    arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) ||
177	    arasan_phy_read(host, STRB_CTRL, &val) ||
178	    arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) ||
179	    arasan_phy_read(host, CLK_CTRL, &val) ||
180	    arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) ||
181	    arasan_phy_read(host, CLKBUF_SEL, &val) ||
182	    arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) ||
183	    arasan_phy_write(host, LEGACY_MODE, MODE_CTRL))
184		return -EBUSY;
185	return 0;
186}
187
188/* Set Arasan PHY for different modes */
189static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap,
190			  u8 drv_type, u8 itap, u8 trim, u8 clk)
191{
192	u8 val;
193	int ret;
194
195	if (mode == HISPD_MODE || mode == HS200_MODE)
196		ret = arasan_phy_write(host, 0x0, MODE_CTRL);
197	else
198		ret = arasan_phy_write(host, mode, MODE_CTRL);
199	if (ret)
200		return ret;
201	if (mode == HS400_MODE || mode == HS200_MODE) {
202		ret = arasan_phy_read(host, IPAD_CTRL1, &val);
203		if (ret)
204			return ret;
205		ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1);
206		if (ret)
207			return ret;
208	}
209	if (mode == LEGACY_MODE) {
210		ret = arasan_phy_write(host, 0x0, OTAP_DELAY);
211		if (ret)
212			return ret;
213		ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
214	} else {
215		ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY);
216		if (ret)
217			return ret;
218		if (mode != HS200_MODE)
219			ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY);
220		else
221			ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
222	}
223	if (ret)
224		return ret;
225	if (mode != LEGACY_MODE) {
226		ret = arasan_phy_write(host, trim, DLL_TRIM);
227		if (ret)
228			return ret;
229	}
230	ret = arasan_phy_write(host, 0, DLL_STATUS);
231	if (ret)
232		return ret;
233	if (mode != LEGACY_MODE) {
234		ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS);
235		if (ret)
236			return ret;
237		ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK);
238		if (ret)
239			return -EBUSY;
240	}
241	return 0;
242}
243
244static int arasan_select_phy_clock(struct sdhci_host *host)
245{
246	struct sdhci_pci_slot *slot = sdhci_priv(host);
247	struct arasan_host *arasan_host = sdhci_pci_priv(slot);
248	u8 clk;
249
250	if (arasan_host->chg_clk == host->mmc->ios.clock)
251		return 0;
252
253	arasan_host->chg_clk = host->mmc->ios.clock;
254	if (host->mmc->ios.clock == 200000000)
255		clk = 0x0;
256	else if (host->mmc->ios.clock == 100000000)
257		clk = 0x2;
258	else if (host->mmc->ios.clock == 50000000)
259		clk = 0x1;
260	else
261		clk = 0x0;
262
263	if (host->mmc_host_ops.hs400_enhanced_strobe) {
264		arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0,
265			       DLLTRM_ICP, clk);
266	} else {
267		switch (host->mmc->ios.timing) {
268		case MMC_TIMING_LEGACY:
269			arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0,
270				       0x0, 0x0);
271			break;
272		case MMC_TIMING_MMC_HS:
273		case MMC_TIMING_SD_HS:
274			arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2,
275				       DLLTRM_ICP, clk);
276			break;
277		case MMC_TIMING_MMC_HS200:
278		case MMC_TIMING_UHS_SDR104:
279			arasan_phy_set(host, HS200_MODE, 0x2,
280				       host->mmc->ios.drv_type, 0x0,
281				       DLLTRM_ICP, clk);
282			break;
283		case MMC_TIMING_MMC_DDR52:
284		case MMC_TIMING_UHS_DDR50:
285			arasan_phy_set(host, DDR50_MODE, 0x1, 0x0,
286				       0x0, DLLTRM_ICP, clk);
287			break;
288		case MMC_TIMING_MMC_HS400:
289			arasan_phy_set(host, HS400_MODE, 0x1,
290				       host->mmc->ios.drv_type, 0xa,
291				       DLLTRM_ICP, clk);
292			break;
293		default:
294			break;
295		}
296	}
297	return 0;
298}
299
300static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot)
301{
302	int err;
303
304	slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA;
305	err = arasan_phy_init(slot->host);
306	if (err)
307		return -ENODEV;
308	return 0;
309}
310
311static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
312{
313	sdhci_set_clock(host, clock);
314
315	/* Change phy settings for the new clock */
316	arasan_select_phy_clock(host);
317}
318
319static const struct sdhci_ops arasan_sdhci_pci_ops = {
320	.set_clock	= arasan_sdhci_set_clock,
321	.enable_dma	= sdhci_pci_enable_dma,
322	.set_bus_width	= sdhci_set_bus_width,
323	.reset		= sdhci_reset,
324	.set_uhs_signaling	= sdhci_set_uhs_signaling,
325};
326
327const struct sdhci_pci_fixes sdhci_arasan = {
328	.probe_slot = arasan_pci_probe_slot,
329	.ops        = &arasan_sdhci_pci_ops,
330	.priv_size  = sizeof(struct arasan_host),
331};
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with
  4 * integrated phy.
  5 *
  6 * Copyright (C) 2017 Arasan Chip Systems Inc.
  7 *
  8 * Author: Atul Garg <agarg@arasan.com>
  9 */
 10
 11#include <linux/pci.h>
 12#include <linux/delay.h>
 13
 14#include "sdhci.h"
 15#include "sdhci-pci.h"
 16
 17/* Extra registers for Arasan SD/SDIO/MMC Host Controller with PHY */
 18#define PHY_ADDR_REG	0x300
 19#define PHY_DAT_REG	0x304
 20
 21#define PHY_WRITE	BIT(8)
 22#define PHY_BUSY	BIT(9)
 23#define DATA_MASK	0xFF
 24
 25/* PHY Specific Registers */
 26#define DLL_STATUS	0x00
 27#define IPAD_CTRL1	0x01
 28#define IPAD_CTRL2	0x02
 29#define IPAD_STS	0x03
 30#define IOREN_CTRL1	0x06
 31#define IOREN_CTRL2	0x07
 32#define IOPU_CTRL1	0x08
 33#define IOPU_CTRL2	0x09
 34#define ITAP_DELAY	0x0C
 35#define OTAP_DELAY	0x0D
 36#define STRB_SEL	0x0E
 37#define CLKBUF_SEL	0x0F
 38#define MODE_CTRL	0x11
 39#define DLL_TRIM	0x12
 40#define CMD_CTRL	0x20
 41#define DATA_CTRL	0x21
 42#define STRB_CTRL	0x22
 43#define CLK_CTRL	0x23
 44#define PHY_CTRL	0x24
 45
 46#define DLL_ENBL	BIT(3)
 47#define RTRIM_EN	BIT(1)
 48#define PDB_ENBL	BIT(1)
 49#define RETB_ENBL	BIT(6)
 50#define ODEN_CMD	BIT(1)
 51#define ODEN_DAT	0xFF
 52#define REN_STRB	BIT(0)
 53#define REN_CMND	BIT(1)
 54#define REN_DATA	0xFF
 55#define PU_CMD		BIT(1)
 56#define PU_DAT		0xFF
 57#define ITAPDLY_EN	BIT(0)
 58#define OTAPDLY_EN	BIT(0)
 59#define OD_REL_CMD	BIT(1)
 60#define OD_REL_DAT	0xFF
 61#define DLLTRM_ICP	0x8
 62#define PDB_CMND	BIT(0)
 63#define PDB_DATA	0xFF
 64#define PDB_STRB	BIT(0)
 65#define PDB_CLOCK	BIT(0)
 66#define CALDONE_MASK	0x10
 67#define DLL_RDY_MASK	0x10
 68#define MAX_CLK_BUF	0x7
 69
 70/* Mode Controls */
 71#define ENHSTRB_MODE	BIT(0)
 72#define HS400_MODE	BIT(1)
 73#define LEGACY_MODE	BIT(2)
 74#define DDR50_MODE	BIT(3)
 75
 76/*
 77 * Controller has no specific bits for HS200/HS.
 78 * Used BIT(4), BIT(5) for software programming.
 79 */
 80#define HS200_MODE	BIT(4)
 81#define HISPD_MODE	BIT(5)
 82
 83#define OTAPDLY(x)	(((x) << 1) | OTAPDLY_EN)
 84#define ITAPDLY(x)	(((x) << 1) | ITAPDLY_EN)
 85#define FREQSEL(x)	(((x) << 5) | DLL_ENBL)
 86#define IOPAD(x, y)	((x) | ((y) << 2))
 87
 88/* Arasan private data */
 89struct arasan_host {
 90	u32 chg_clk;
 91};
 92
 93static int arasan_phy_addr_poll(struct sdhci_host *host, u32 offset, u32 mask)
 94{
 95	ktime_t timeout = ktime_add_us(ktime_get(), 100);
 96	bool failed;
 97	u8 val = 0;
 98
 99	while (1) {
100		failed = ktime_after(ktime_get(), timeout);
101		val = sdhci_readw(host, PHY_ADDR_REG);
102		if (!(val & mask))
103			return 0;
104		if (failed)
105			return -EBUSY;
106	}
107}
108
109static int arasan_phy_write(struct sdhci_host *host, u8 data, u8 offset)
110{
111	sdhci_writew(host, data, PHY_DAT_REG);
112	sdhci_writew(host, (PHY_WRITE | offset), PHY_ADDR_REG);
113	return arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
114}
115
116static int arasan_phy_read(struct sdhci_host *host, u8 offset, u8 *data)
117{
118	int ret;
119
120	sdhci_writew(host, 0, PHY_DAT_REG);
121	sdhci_writew(host, offset, PHY_ADDR_REG);
122	ret = arasan_phy_addr_poll(host, PHY_ADDR_REG, PHY_BUSY);
123
124	/* Masking valid data bits */
125	*data = sdhci_readw(host, PHY_DAT_REG) & DATA_MASK;
126	return ret;
127}
128
129static int arasan_phy_sts_poll(struct sdhci_host *host, u32 offset, u32 mask)
130{
131	int ret;
132	ktime_t timeout = ktime_add_us(ktime_get(), 100);
133	bool failed;
134	u8 val = 0;
135
136	while (1) {
137		failed = ktime_after(ktime_get(), timeout);
138		ret = arasan_phy_read(host, offset, &val);
139		if (ret)
140			return -EBUSY;
141		else if (val & mask)
142			return 0;
143		if (failed)
144			return -EBUSY;
145	}
146}
147
148/* Initialize the Arasan PHY */
149static int arasan_phy_init(struct sdhci_host *host)
150{
151	int ret;
152	u8 val;
153
154	/* Program IOPADs and wait for calibration to be done */
155	if (arasan_phy_read(host, IPAD_CTRL1, &val) ||
156	    arasan_phy_write(host, val | RETB_ENBL | PDB_ENBL, IPAD_CTRL1) ||
157	    arasan_phy_read(host, IPAD_CTRL2, &val) ||
158	    arasan_phy_write(host, val | RTRIM_EN, IPAD_CTRL2))
159		return -EBUSY;
160	ret = arasan_phy_sts_poll(host, IPAD_STS, CALDONE_MASK);
161	if (ret)
162		return -EBUSY;
163
164	/* Program CMD/Data lines */
165	if (arasan_phy_read(host, IOREN_CTRL1, &val) ||
166	    arasan_phy_write(host, val | REN_CMND | REN_STRB, IOREN_CTRL1) ||
167	    arasan_phy_read(host, IOPU_CTRL1, &val) ||
168	    arasan_phy_write(host, val | PU_CMD, IOPU_CTRL1) ||
169	    arasan_phy_read(host, CMD_CTRL, &val) ||
170	    arasan_phy_write(host, val | PDB_CMND, CMD_CTRL) ||
171	    arasan_phy_read(host, IOREN_CTRL2, &val) ||
172	    arasan_phy_write(host, val | REN_DATA, IOREN_CTRL2) ||
173	    arasan_phy_read(host, IOPU_CTRL2, &val) ||
174	    arasan_phy_write(host, val | PU_DAT, IOPU_CTRL2) ||
175	    arasan_phy_read(host, DATA_CTRL, &val) ||
176	    arasan_phy_write(host, val | PDB_DATA, DATA_CTRL) ||
177	    arasan_phy_read(host, STRB_CTRL, &val) ||
178	    arasan_phy_write(host, val | PDB_STRB, STRB_CTRL) ||
179	    arasan_phy_read(host, CLK_CTRL, &val) ||
180	    arasan_phy_write(host, val | PDB_CLOCK, CLK_CTRL) ||
181	    arasan_phy_read(host, CLKBUF_SEL, &val) ||
182	    arasan_phy_write(host, val | MAX_CLK_BUF, CLKBUF_SEL) ||
183	    arasan_phy_write(host, LEGACY_MODE, MODE_CTRL))
184		return -EBUSY;
185	return 0;
186}
187
188/* Set Arasan PHY for different modes */
189static int arasan_phy_set(struct sdhci_host *host, u8 mode, u8 otap,
190			  u8 drv_type, u8 itap, u8 trim, u8 clk)
191{
192	u8 val;
193	int ret;
194
195	if (mode == HISPD_MODE || mode == HS200_MODE)
196		ret = arasan_phy_write(host, 0x0, MODE_CTRL);
197	else
198		ret = arasan_phy_write(host, mode, MODE_CTRL);
199	if (ret)
200		return ret;
201	if (mode == HS400_MODE || mode == HS200_MODE) {
202		ret = arasan_phy_read(host, IPAD_CTRL1, &val);
203		if (ret)
204			return ret;
205		ret = arasan_phy_write(host, IOPAD(val, drv_type), IPAD_CTRL1);
206		if (ret)
207			return ret;
208	}
209	if (mode == LEGACY_MODE) {
210		ret = arasan_phy_write(host, 0x0, OTAP_DELAY);
211		if (ret)
212			return ret;
213		ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
214	} else {
215		ret = arasan_phy_write(host, OTAPDLY(otap), OTAP_DELAY);
216		if (ret)
217			return ret;
218		if (mode != HS200_MODE)
219			ret = arasan_phy_write(host, ITAPDLY(itap), ITAP_DELAY);
220		else
221			ret = arasan_phy_write(host, 0x0, ITAP_DELAY);
222	}
223	if (ret)
224		return ret;
225	if (mode != LEGACY_MODE) {
226		ret = arasan_phy_write(host, trim, DLL_TRIM);
227		if (ret)
228			return ret;
229	}
230	ret = arasan_phy_write(host, 0, DLL_STATUS);
231	if (ret)
232		return ret;
233	if (mode != LEGACY_MODE) {
234		ret = arasan_phy_write(host, FREQSEL(clk), DLL_STATUS);
235		if (ret)
236			return ret;
237		ret = arasan_phy_sts_poll(host, DLL_STATUS, DLL_RDY_MASK);
238		if (ret)
239			return -EBUSY;
240	}
241	return 0;
242}
243
244static int arasan_select_phy_clock(struct sdhci_host *host)
245{
246	struct sdhci_pci_slot *slot = sdhci_priv(host);
247	struct arasan_host *arasan_host = sdhci_pci_priv(slot);
248	u8 clk;
249
250	if (arasan_host->chg_clk == host->mmc->ios.clock)
251		return 0;
252
253	arasan_host->chg_clk = host->mmc->ios.clock;
254	if (host->mmc->ios.clock == 200000000)
255		clk = 0x0;
256	else if (host->mmc->ios.clock == 100000000)
257		clk = 0x2;
258	else if (host->mmc->ios.clock == 50000000)
259		clk = 0x1;
260	else
261		clk = 0x0;
262
263	if (host->mmc_host_ops.hs400_enhanced_strobe) {
264		arasan_phy_set(host, ENHSTRB_MODE, 1, 0x0, 0x0,
265			       DLLTRM_ICP, clk);
266	} else {
267		switch (host->mmc->ios.timing) {
268		case MMC_TIMING_LEGACY:
269			arasan_phy_set(host, LEGACY_MODE, 0x0, 0x0, 0x0,
270				       0x0, 0x0);
271			break;
272		case MMC_TIMING_MMC_HS:
273		case MMC_TIMING_SD_HS:
274			arasan_phy_set(host, HISPD_MODE, 0x3, 0x0, 0x2,
275				       DLLTRM_ICP, clk);
276			break;
277		case MMC_TIMING_MMC_HS200:
278		case MMC_TIMING_UHS_SDR104:
279			arasan_phy_set(host, HS200_MODE, 0x2,
280				       host->mmc->ios.drv_type, 0x0,
281				       DLLTRM_ICP, clk);
282			break;
283		case MMC_TIMING_MMC_DDR52:
284		case MMC_TIMING_UHS_DDR50:
285			arasan_phy_set(host, DDR50_MODE, 0x1, 0x0,
286				       0x0, DLLTRM_ICP, clk);
287			break;
288		case MMC_TIMING_MMC_HS400:
289			arasan_phy_set(host, HS400_MODE, 0x1,
290				       host->mmc->ios.drv_type, 0xa,
291				       DLLTRM_ICP, clk);
292			break;
293		default:
294			break;
295		}
296	}
297	return 0;
298}
299
300static int arasan_pci_probe_slot(struct sdhci_pci_slot *slot)
301{
302	int err;
303
304	slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_8_BIT_DATA;
305	err = arasan_phy_init(slot->host);
306	if (err)
307		return -ENODEV;
308	return 0;
309}
310
311static void arasan_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
312{
313	sdhci_set_clock(host, clock);
314
315	/* Change phy settings for the new clock */
316	arasan_select_phy_clock(host);
317}
318
319static const struct sdhci_ops arasan_sdhci_pci_ops = {
320	.set_clock	= arasan_sdhci_set_clock,
321	.enable_dma	= sdhci_pci_enable_dma,
322	.set_bus_width	= sdhci_set_bus_width,
323	.reset		= sdhci_reset,
324	.set_uhs_signaling	= sdhci_set_uhs_signaling,
325};
326
327const struct sdhci_pci_fixes sdhci_arasan = {
328	.probe_slot = arasan_pci_probe_slot,
329	.ops        = &arasan_sdhci_pci_ops,
330	.priv_size  = sizeof(struct arasan_host),
331};