xref: /rk3399_rockchip-uboot/drivers/spi/kirkwood_spi.c (revision ab86434d690d9030cbfb0f21d7d14bdf1ca9f62e)
15710de45SPrafulla Wadaskar /*
25710de45SPrafulla Wadaskar  * (C) Copyright 2009
35710de45SPrafulla Wadaskar  * Marvell Semiconductor <www.marvell.com>
45710de45SPrafulla Wadaskar  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
55710de45SPrafulla Wadaskar  *
65710de45SPrafulla Wadaskar  * Derived from drivers/spi/mpc8xxx_spi.c
75710de45SPrafulla Wadaskar  *
81a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
95710de45SPrafulla Wadaskar  */
105710de45SPrafulla Wadaskar 
115710de45SPrafulla Wadaskar #include <common.h>
129985bdb1SStefan Roese #include <dm.h>
135710de45SPrafulla Wadaskar #include <malloc.h>
145710de45SPrafulla Wadaskar #include <spi.h>
15a7efd719SLei Wen #include <asm/io.h>
163dc23f78SStefan Roese #include <asm/arch/soc.h>
174aceea20SStefan Roese #ifdef CONFIG_KIRKWOOD
185710de45SPrafulla Wadaskar #include <asm/arch/mpp.h>
194aceea20SStefan Roese #endif
203e972cb9SStefan Roese #include <asm/arch-mvebu/spi.h>
215710de45SPrafulla Wadaskar 
_spi_cs_activate(struct kwspi_registers * reg)229985bdb1SStefan Roese static void _spi_cs_activate(struct kwspi_registers *reg)
239985bdb1SStefan Roese {
249985bdb1SStefan Roese 	setbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
259985bdb1SStefan Roese }
269985bdb1SStefan Roese 
_spi_cs_deactivate(struct kwspi_registers * reg)279985bdb1SStefan Roese static void _spi_cs_deactivate(struct kwspi_registers *reg)
289985bdb1SStefan Roese {
299985bdb1SStefan Roese 	clrbits_le32(&reg->ctrl, KWSPI_CSN_ACT);
309985bdb1SStefan Roese }
319985bdb1SStefan Roese 
_spi_xfer(struct kwspi_registers * reg,unsigned int bitlen,const void * dout,void * din,unsigned long flags)329985bdb1SStefan Roese static int _spi_xfer(struct kwspi_registers *reg, unsigned int bitlen,
339985bdb1SStefan Roese 		     const void *dout, void *din, unsigned long flags)
349985bdb1SStefan Roese {
359985bdb1SStefan Roese 	unsigned int tmpdout, tmpdin;
369985bdb1SStefan Roese 	int tm, isread = 0;
379985bdb1SStefan Roese 
389985bdb1SStefan Roese 	debug("spi_xfer: dout %p din %p bitlen %u\n", dout, din, bitlen);
399985bdb1SStefan Roese 
409985bdb1SStefan Roese 	if (flags & SPI_XFER_BEGIN)
419985bdb1SStefan Roese 		_spi_cs_activate(reg);
429985bdb1SStefan Roese 
439985bdb1SStefan Roese 	/*
449985bdb1SStefan Roese 	 * handle data in 8-bit chunks
459985bdb1SStefan Roese 	 * TBD: 2byte xfer mode to be enabled
469985bdb1SStefan Roese 	 */
479985bdb1SStefan Roese 	clrsetbits_le32(&reg->cfg, KWSPI_XFERLEN_MASK, KWSPI_XFERLEN_1BYTE);
489985bdb1SStefan Roese 
499985bdb1SStefan Roese 	while (bitlen > 4) {
509985bdb1SStefan Roese 		debug("loopstart bitlen %d\n", bitlen);
519985bdb1SStefan Roese 		tmpdout = 0;
529985bdb1SStefan Roese 
539985bdb1SStefan Roese 		/* Shift data so it's msb-justified */
549985bdb1SStefan Roese 		if (dout)
559985bdb1SStefan Roese 			tmpdout = *(u32 *)dout & 0xff;
569985bdb1SStefan Roese 
579985bdb1SStefan Roese 		clrbits_le32(&reg->irq_cause, KWSPI_SMEMRDIRQ);
589985bdb1SStefan Roese 		writel(tmpdout, &reg->dout);	/* Write the data out */
599985bdb1SStefan Roese 		debug("*** spi_xfer: ... %08x written, bitlen %d\n",
609985bdb1SStefan Roese 		      tmpdout, bitlen);
619985bdb1SStefan Roese 
629985bdb1SStefan Roese 		/*
639985bdb1SStefan Roese 		 * Wait for SPI transmit to get out
649985bdb1SStefan Roese 		 * or time out (1 second = 1000 ms)
659985bdb1SStefan Roese 		 * The NE event must be read and cleared first
669985bdb1SStefan Roese 		 */
679985bdb1SStefan Roese 		for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
689985bdb1SStefan Roese 			if (readl(&reg->irq_cause) & KWSPI_SMEMRDIRQ) {
699985bdb1SStefan Roese 				isread = 1;
709985bdb1SStefan Roese 				tmpdin = readl(&reg->din);
719985bdb1SStefan Roese 				debug("spi_xfer: din %p..%08x read\n",
729985bdb1SStefan Roese 				      din, tmpdin);
739985bdb1SStefan Roese 
749985bdb1SStefan Roese 				if (din) {
759985bdb1SStefan Roese 					*((u8 *)din) = (u8)tmpdin;
769985bdb1SStefan Roese 					din += 1;
779985bdb1SStefan Roese 				}
789985bdb1SStefan Roese 				if (dout)
799985bdb1SStefan Roese 					dout += 1;
809985bdb1SStefan Roese 				bitlen -= 8;
819985bdb1SStefan Roese 			}
829985bdb1SStefan Roese 			if (isread)
839985bdb1SStefan Roese 				break;
849985bdb1SStefan Roese 		}
859985bdb1SStefan Roese 		if (tm >= KWSPI_TIMEOUT)
869985bdb1SStefan Roese 			printf("*** spi_xfer: Time out during SPI transfer\n");
879985bdb1SStefan Roese 
889985bdb1SStefan Roese 		debug("loopend bitlen %d\n", bitlen);
899985bdb1SStefan Roese 	}
909985bdb1SStefan Roese 
919985bdb1SStefan Roese 	if (flags & SPI_XFER_END)
929985bdb1SStefan Roese 		_spi_cs_deactivate(reg);
939985bdb1SStefan Roese 
949985bdb1SStefan Roese 	return 0;
959985bdb1SStefan Roese }
969985bdb1SStefan Roese 
979985bdb1SStefan Roese #ifndef CONFIG_DM_SPI
989985bdb1SStefan Roese 
994fd7717eSStefan Roese static struct kwspi_registers *spireg =
1004fd7717eSStefan Roese 	(struct kwspi_registers *)MVEBU_SPI_BASE;
1015710de45SPrafulla Wadaskar 
1024aceea20SStefan Roese #ifdef CONFIG_KIRKWOOD
1030299046eSStefan Roese static u32 cs_spi_mpp_back[2];
1044aceea20SStefan Roese #endif
105ca880679SValentin Longchamp 
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)1065710de45SPrafulla Wadaskar struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
1075710de45SPrafulla Wadaskar 				unsigned int max_hz, unsigned int mode)
1085710de45SPrafulla Wadaskar {
1095710de45SPrafulla Wadaskar 	struct spi_slave *slave;
1105710de45SPrafulla Wadaskar 	u32 data;
1114aceea20SStefan Roese #ifdef CONFIG_KIRKWOOD
1129d86f0c3SAlbert ARIBAUD 	static const u32 kwspi_mpp_config[2][2] = {
1139d86f0c3SAlbert ARIBAUD 		{ MPP0_SPI_SCn, 0 }, /* if cs == 0 */
1149d86f0c3SAlbert ARIBAUD 		{ MPP7_SPI_SCn, 0 } /* if cs != 0 */
1159d86f0c3SAlbert ARIBAUD 	};
1164aceea20SStefan Roese #endif
1175710de45SPrafulla Wadaskar 
1185710de45SPrafulla Wadaskar 	if (!spi_cs_is_valid(bus, cs))
1195710de45SPrafulla Wadaskar 		return NULL;
1205710de45SPrafulla Wadaskar 
121d3504feeSSimon Glass 	slave = spi_alloc_slave_base(bus, cs);
1225710de45SPrafulla Wadaskar 	if (!slave)
1235710de45SPrafulla Wadaskar 		return NULL;
1245710de45SPrafulla Wadaskar 
125c032174fSStefan Roese 	writel(KWSPI_SMEMRDY, &spireg->ctrl);
1265710de45SPrafulla Wadaskar 
1275710de45SPrafulla Wadaskar 	/* calculate spi clock prescaller using max_hz */
1288203b201SValentin Longchamp 	data = ((CONFIG_SYS_TCLK / 2) / max_hz) + 0x10;
1298203b201SValentin Longchamp 	data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data;
1308203b201SValentin Longchamp 	data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data;
1315710de45SPrafulla Wadaskar 
1325710de45SPrafulla Wadaskar 	/* program spi clock prescaller using max_hz */
1335710de45SPrafulla Wadaskar 	writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
1345710de45SPrafulla Wadaskar 	debug("data = 0x%08x\n", data);
1355710de45SPrafulla Wadaskar 
1365710de45SPrafulla Wadaskar 	writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause);
1373f843551SIan Campbell 	writel(KWSPI_IRQMASK, &spireg->irq_mask);
1385710de45SPrafulla Wadaskar 
1394aceea20SStefan Roese #ifdef CONFIG_KIRKWOOD
1405710de45SPrafulla Wadaskar 	/* program mpp registers to select  SPI_CSn */
1419d86f0c3SAlbert ARIBAUD 	kirkwood_mpp_conf(kwspi_mpp_config[cs ? 1 : 0], cs_spi_mpp_back);
1424aceea20SStefan Roese #endif
1435710de45SPrafulla Wadaskar 
1445710de45SPrafulla Wadaskar 	return slave;
1455710de45SPrafulla Wadaskar }
1465710de45SPrafulla Wadaskar 
spi_free_slave(struct spi_slave * slave)1475710de45SPrafulla Wadaskar void spi_free_slave(struct spi_slave *slave)
1485710de45SPrafulla Wadaskar {
1494aceea20SStefan Roese #ifdef CONFIG_KIRKWOOD
150ca880679SValentin Longchamp 	kirkwood_mpp_conf(cs_spi_mpp_back, NULL);
1514aceea20SStefan Roese #endif
1525710de45SPrafulla Wadaskar 	free(slave);
1535710de45SPrafulla Wadaskar }
1545710de45SPrafulla Wadaskar 
155ac486e3bSValentin Longchamp #if defined(CONFIG_SYS_KW_SPI_MPP)
156ac486e3bSValentin Longchamp u32 spi_mpp_backup[4];
157ac486e3bSValentin Longchamp #endif
158ac486e3bSValentin Longchamp 
board_spi_claim_bus(struct spi_slave * slave)15924934feaSValentin Longchamp __attribute__((weak)) int board_spi_claim_bus(struct spi_slave *slave)
16024934feaSValentin Longchamp {
16124934feaSValentin Longchamp 	return 0;
16224934feaSValentin Longchamp }
16324934feaSValentin Longchamp 
spi_claim_bus(struct spi_slave * slave)1645710de45SPrafulla Wadaskar int spi_claim_bus(struct spi_slave *slave)
1655710de45SPrafulla Wadaskar {
166ac486e3bSValentin Longchamp #if defined(CONFIG_SYS_KW_SPI_MPP)
167ac486e3bSValentin Longchamp 	u32 config;
168ac486e3bSValentin Longchamp 	u32 spi_mpp_config[4];
169ac486e3bSValentin Longchamp 
170ac486e3bSValentin Longchamp 	config = CONFIG_SYS_KW_SPI_MPP;
171ac486e3bSValentin Longchamp 
172ac486e3bSValentin Longchamp 	if (config & MOSI_MPP6)
173ac486e3bSValentin Longchamp 		spi_mpp_config[0] = MPP6_SPI_MOSI;
174ac486e3bSValentin Longchamp 	else
175ac486e3bSValentin Longchamp 		spi_mpp_config[0] = MPP1_SPI_MOSI;
176ac486e3bSValentin Longchamp 
177ac486e3bSValentin Longchamp 	if (config & SCK_MPP10)
178ac486e3bSValentin Longchamp 		spi_mpp_config[1] = MPP10_SPI_SCK;
179ac486e3bSValentin Longchamp 	else
180ac486e3bSValentin Longchamp 		spi_mpp_config[1] = MPP2_SPI_SCK;
181ac486e3bSValentin Longchamp 
182ac486e3bSValentin Longchamp 	if (config & MISO_MPP11)
183ac486e3bSValentin Longchamp 		spi_mpp_config[2] = MPP11_SPI_MISO;
184ac486e3bSValentin Longchamp 	else
185ac486e3bSValentin Longchamp 		spi_mpp_config[2] = MPP3_SPI_MISO;
186ac486e3bSValentin Longchamp 
187ac486e3bSValentin Longchamp 	spi_mpp_config[3] = 0;
188ac486e3bSValentin Longchamp 	spi_mpp_backup[3] = 0;
189ac486e3bSValentin Longchamp 
190ac486e3bSValentin Longchamp 	/* set new spi mpp and save current mpp config */
191ac486e3bSValentin Longchamp 	kirkwood_mpp_conf(spi_mpp_config, spi_mpp_backup);
192ac486e3bSValentin Longchamp #endif
193ac486e3bSValentin Longchamp 
19424934feaSValentin Longchamp 	return board_spi_claim_bus(slave);
19524934feaSValentin Longchamp }
19624934feaSValentin Longchamp 
board_spi_release_bus(struct spi_slave * slave)19724934feaSValentin Longchamp __attribute__((weak)) void board_spi_release_bus(struct spi_slave *slave)
19824934feaSValentin Longchamp {
1995710de45SPrafulla Wadaskar }
2005710de45SPrafulla Wadaskar 
spi_release_bus(struct spi_slave * slave)2015710de45SPrafulla Wadaskar void spi_release_bus(struct spi_slave *slave)
2025710de45SPrafulla Wadaskar {
203ac486e3bSValentin Longchamp #if defined(CONFIG_SYS_KW_SPI_MPP)
204ac486e3bSValentin Longchamp 	kirkwood_mpp_conf(spi_mpp_backup, NULL);
205ac486e3bSValentin Longchamp #endif
20624934feaSValentin Longchamp 
20724934feaSValentin Longchamp 	board_spi_release_bus(slave);
2085710de45SPrafulla Wadaskar }
2095710de45SPrafulla Wadaskar 
2105710de45SPrafulla Wadaskar #ifndef CONFIG_SPI_CS_IS_VALID
2115710de45SPrafulla Wadaskar /*
2125710de45SPrafulla Wadaskar  * you can define this function board specific
2135710de45SPrafulla Wadaskar  * define above CONFIG in board specific config file and
2145710de45SPrafulla Wadaskar  * provide the function in board specific src file
2155710de45SPrafulla Wadaskar  */
spi_cs_is_valid(unsigned int bus,unsigned int cs)2165710de45SPrafulla Wadaskar int spi_cs_is_valid(unsigned int bus, unsigned int cs)
2175710de45SPrafulla Wadaskar {
218bf9b86dcSStefan Roese 	return bus == 0 && (cs == 0 || cs == 1);
2195710de45SPrafulla Wadaskar }
2205710de45SPrafulla Wadaskar #endif
2215710de45SPrafulla Wadaskar 
spi_init(void)222efa4e43aSMichael Walle void spi_init(void)
223efa4e43aSMichael Walle {
224efa4e43aSMichael Walle }
225efa4e43aSMichael Walle 
spi_cs_activate(struct spi_slave * slave)2265710de45SPrafulla Wadaskar void spi_cs_activate(struct spi_slave *slave)
2275710de45SPrafulla Wadaskar {
22818dd3b22SStefan Roese 	_spi_cs_activate(spireg);
2295710de45SPrafulla Wadaskar }
2305710de45SPrafulla Wadaskar 
spi_cs_deactivate(struct spi_slave * slave)2315710de45SPrafulla Wadaskar void spi_cs_deactivate(struct spi_slave *slave)
2325710de45SPrafulla Wadaskar {
23318dd3b22SStefan Roese 	_spi_cs_deactivate(spireg);
2345710de45SPrafulla Wadaskar }
2355710de45SPrafulla Wadaskar 
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)23618dd3b22SStefan Roese int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
23718dd3b22SStefan Roese 	     const void *dout, void *din, unsigned long flags)
23818dd3b22SStefan Roese {
23918dd3b22SStefan Roese 	return _spi_xfer(spireg, bitlen, dout, din, flags);
24018dd3b22SStefan Roese }
2419985bdb1SStefan Roese 
2429985bdb1SStefan Roese #else
2439985bdb1SStefan Roese 
2449985bdb1SStefan Roese /* Here now the DM part */
2459985bdb1SStefan Roese 
246*ab86434dSChris Packham struct mvebu_spi_dev {
247*ab86434dSChris Packham 	bool			is_errata_50mhz_ac;
248*ab86434dSChris Packham };
249*ab86434dSChris Packham 
2509985bdb1SStefan Roese struct mvebu_spi_platdata {
2519985bdb1SStefan Roese 	struct kwspi_registers *spireg;
2529985bdb1SStefan Roese };
2539985bdb1SStefan Roese 
2549985bdb1SStefan Roese struct mvebu_spi_priv {
2559985bdb1SStefan Roese 	struct kwspi_registers *spireg;
2569985bdb1SStefan Roese };
2579985bdb1SStefan Roese 
mvebu_spi_set_speed(struct udevice * bus,uint hz)2589985bdb1SStefan Roese static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
2599985bdb1SStefan Roese {
2609985bdb1SStefan Roese 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
2619985bdb1SStefan Roese 	struct kwspi_registers *reg = plat->spireg;
2629985bdb1SStefan Roese 	u32 data;
2639985bdb1SStefan Roese 
2649985bdb1SStefan Roese 	/* calculate spi clock prescaller using max_hz */
2659985bdb1SStefan Roese 	data = ((CONFIG_SYS_TCLK / 2) / hz) + 0x10;
2669985bdb1SStefan Roese 	data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data;
2679985bdb1SStefan Roese 	data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data;
2689985bdb1SStefan Roese 
2699985bdb1SStefan Roese 	/* program spi clock prescaler using max_hz */
2709985bdb1SStefan Roese 	writel(KWSPI_ADRLEN_3BYTE | data, &reg->cfg);
2719985bdb1SStefan Roese 	debug("data = 0x%08x\n", data);
2729985bdb1SStefan Roese 
2739985bdb1SStefan Roese 	return 0;
2749985bdb1SStefan Roese }
2759985bdb1SStefan Roese 
mvebu_spi_50mhz_ac_timing_erratum(struct udevice * bus,uint mode)276*ab86434dSChris Packham static void mvebu_spi_50mhz_ac_timing_erratum(struct udevice *bus, uint mode)
277*ab86434dSChris Packham {
278*ab86434dSChris Packham 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
279*ab86434dSChris Packham 	struct kwspi_registers *reg = plat->spireg;
280*ab86434dSChris Packham 	u32 data;
281*ab86434dSChris Packham 
282*ab86434dSChris Packham 	/*
283*ab86434dSChris Packham 	 * Erratum description: (Erratum NO. FE-9144572) The device
284*ab86434dSChris Packham 	 * SPI interface supports frequencies of up to 50 MHz.
285*ab86434dSChris Packham 	 * However, due to this erratum, when the device core clock is
286*ab86434dSChris Packham 	 * 250 MHz and the SPI interfaces is configured for 50MHz SPI
287*ab86434dSChris Packham 	 * clock and CPOL=CPHA=1 there might occur data corruption on
288*ab86434dSChris Packham 	 * reads from the SPI device.
289*ab86434dSChris Packham 	 * Erratum Workaround:
290*ab86434dSChris Packham 	 * Work in one of the following configurations:
291*ab86434dSChris Packham 	 * 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
292*ab86434dSChris Packham 	 * Register".
293*ab86434dSChris Packham 	 * 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
294*ab86434dSChris Packham 	 * Register" before setting the interface.
295*ab86434dSChris Packham 	 */
296*ab86434dSChris Packham 	data = readl(&reg->timing1);
297*ab86434dSChris Packham 	data &= ~KW_SPI_TMISO_SAMPLE_MASK;
298*ab86434dSChris Packham 
299*ab86434dSChris Packham 	if (CONFIG_SYS_TCLK == 250000000 &&
300*ab86434dSChris Packham 	    mode & SPI_CPOL &&
301*ab86434dSChris Packham 	    mode & SPI_CPHA)
302*ab86434dSChris Packham 		data |= KW_SPI_TMISO_SAMPLE_2;
303*ab86434dSChris Packham 	else
304*ab86434dSChris Packham 		data |= KW_SPI_TMISO_SAMPLE_1;
305*ab86434dSChris Packham 
306*ab86434dSChris Packham 	writel(data, &reg->timing1);
307*ab86434dSChris Packham }
308*ab86434dSChris Packham 
mvebu_spi_set_mode(struct udevice * bus,uint mode)3099985bdb1SStefan Roese static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
3109985bdb1SStefan Roese {
311ebfa18cbSChris Packham 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
312ebfa18cbSChris Packham 	struct kwspi_registers *reg = plat->spireg;
313*ab86434dSChris Packham 	const struct mvebu_spi_dev *drvdata;
314ebfa18cbSChris Packham 	u32 data = readl(&reg->cfg);
315ebfa18cbSChris Packham 
316ebfa18cbSChris Packham 	data &= ~(KWSPI_CPHA | KWSPI_CPOL | KWSPI_RXLSBF | KWSPI_TXLSBF);
317ebfa18cbSChris Packham 
318ebfa18cbSChris Packham 	if (mode & SPI_CPHA)
319ebfa18cbSChris Packham 		data |= KWSPI_CPHA;
320ebfa18cbSChris Packham 	if (mode & SPI_CPOL)
321ebfa18cbSChris Packham 		data |= KWSPI_CPOL;
322ebfa18cbSChris Packham 	if (mode & SPI_LSB_FIRST)
323ebfa18cbSChris Packham 		data |= (KWSPI_RXLSBF | KWSPI_TXLSBF);
324ebfa18cbSChris Packham 
325ebfa18cbSChris Packham 	writel(data, &reg->cfg);
326ebfa18cbSChris Packham 
327*ab86434dSChris Packham 	drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus);
328*ab86434dSChris Packham 	if (drvdata->is_errata_50mhz_ac)
329*ab86434dSChris Packham 		mvebu_spi_50mhz_ac_timing_erratum(bus, mode);
330*ab86434dSChris Packham 
3319985bdb1SStefan Roese 	return 0;
3329985bdb1SStefan Roese }
3339985bdb1SStefan Roese 
mvebu_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)3349985bdb1SStefan Roese static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen,
3359985bdb1SStefan Roese 			  const void *dout, void *din, unsigned long flags)
3369985bdb1SStefan Roese {
3379985bdb1SStefan Roese 	struct udevice *bus = dev->parent;
3389985bdb1SStefan Roese 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
3399985bdb1SStefan Roese 
3409985bdb1SStefan Roese 	return _spi_xfer(plat->spireg, bitlen, dout, din, flags);
3419985bdb1SStefan Roese }
3429985bdb1SStefan Roese 
mvebu_spi_claim_bus(struct udevice * dev)3439fc56631SStefan Roese static int mvebu_spi_claim_bus(struct udevice *dev)
3449fc56631SStefan Roese {
3459fc56631SStefan Roese 	struct udevice *bus = dev->parent;
3469fc56631SStefan Roese 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
3479fc56631SStefan Roese 
3489fc56631SStefan Roese 	/* Configure the chip-select in the CTRL register */
3499fc56631SStefan Roese 	clrsetbits_le32(&plat->spireg->ctrl,
3509fc56631SStefan Roese 			KWSPI_CS_MASK << KWSPI_CS_SHIFT,
3519fc56631SStefan Roese 			spi_chip_select(dev) << KWSPI_CS_SHIFT);
3529fc56631SStefan Roese 
3539fc56631SStefan Roese 	return 0;
3549fc56631SStefan Roese }
3559fc56631SStefan Roese 
mvebu_spi_probe(struct udevice * bus)3569985bdb1SStefan Roese static int mvebu_spi_probe(struct udevice *bus)
3579985bdb1SStefan Roese {
3589985bdb1SStefan Roese 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
3599985bdb1SStefan Roese 	struct kwspi_registers *reg = plat->spireg;
3609985bdb1SStefan Roese 
3619985bdb1SStefan Roese 	writel(KWSPI_SMEMRDY, &reg->ctrl);
3629985bdb1SStefan Roese 	writel(KWSPI_SMEMRDIRQ, &reg->irq_cause);
3639985bdb1SStefan Roese 	writel(KWSPI_IRQMASK, &reg->irq_mask);
3649985bdb1SStefan Roese 
3659985bdb1SStefan Roese 	return 0;
3669985bdb1SStefan Roese }
3679985bdb1SStefan Roese 
mvebu_spi_ofdata_to_platdata(struct udevice * bus)3689985bdb1SStefan Roese static int mvebu_spi_ofdata_to_platdata(struct udevice *bus)
3699985bdb1SStefan Roese {
3709985bdb1SStefan Roese 	struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
3719985bdb1SStefan Roese 
372a821c4afSSimon Glass 	plat->spireg = (struct kwspi_registers *)devfdt_get_addr(bus);
3739985bdb1SStefan Roese 
3749985bdb1SStefan Roese 	return 0;
3759985bdb1SStefan Roese }
3769985bdb1SStefan Roese 
3779985bdb1SStefan Roese static const struct dm_spi_ops mvebu_spi_ops = {
3789fc56631SStefan Roese 	.claim_bus	= mvebu_spi_claim_bus,
3799985bdb1SStefan Roese 	.xfer		= mvebu_spi_xfer,
3809985bdb1SStefan Roese 	.set_speed	= mvebu_spi_set_speed,
3819985bdb1SStefan Roese 	.set_mode	= mvebu_spi_set_mode,
3829985bdb1SStefan Roese 	/*
3839985bdb1SStefan Roese 	 * cs_info is not needed, since we require all chip selects to be
3849985bdb1SStefan Roese 	 * in the device tree explicitly
3859985bdb1SStefan Roese 	 */
3869985bdb1SStefan Roese };
3879985bdb1SStefan Roese 
388*ab86434dSChris Packham static const struct mvebu_spi_dev armada_xp_spi_dev_data = {
389*ab86434dSChris Packham 	.is_errata_50mhz_ac = false,
390*ab86434dSChris Packham };
391*ab86434dSChris Packham 
392*ab86434dSChris Packham static const struct mvebu_spi_dev armada_375_spi_dev_data = {
393*ab86434dSChris Packham 	.is_errata_50mhz_ac = false,
394*ab86434dSChris Packham };
395*ab86434dSChris Packham 
396*ab86434dSChris Packham static const struct mvebu_spi_dev armada_380_spi_dev_data = {
397*ab86434dSChris Packham 	.is_errata_50mhz_ac = true,
398*ab86434dSChris Packham };
399*ab86434dSChris Packham 
4009985bdb1SStefan Roese static const struct udevice_id mvebu_spi_ids[] = {
401*ab86434dSChris Packham 	{
402*ab86434dSChris Packham 		.compatible = "marvell,armada-375-spi",
403*ab86434dSChris Packham 		.data = (ulong)&armada_375_spi_dev_data
404*ab86434dSChris Packham 	},
405*ab86434dSChris Packham 	{
406*ab86434dSChris Packham 		.compatible = "marvell,armada-380-spi",
407*ab86434dSChris Packham 		.data = (ulong)&armada_380_spi_dev_data
408*ab86434dSChris Packham 	},
409*ab86434dSChris Packham 	{
410*ab86434dSChris Packham 		.compatible = "marvell,armada-xp-spi",
411*ab86434dSChris Packham 		.data = (ulong)&armada_xp_spi_dev_data
412*ab86434dSChris Packham 	},
4139985bdb1SStefan Roese 	{ }
4149985bdb1SStefan Roese };
4159985bdb1SStefan Roese 
4169985bdb1SStefan Roese U_BOOT_DRIVER(mvebu_spi) = {
4179985bdb1SStefan Roese 	.name = "mvebu_spi",
4189985bdb1SStefan Roese 	.id = UCLASS_SPI,
4199985bdb1SStefan Roese 	.of_match = mvebu_spi_ids,
4209985bdb1SStefan Roese 	.ops = &mvebu_spi_ops,
4219985bdb1SStefan Roese 	.ofdata_to_platdata = mvebu_spi_ofdata_to_platdata,
4229985bdb1SStefan Roese 	.platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata),
4239985bdb1SStefan Roese 	.priv_auto_alloc_size = sizeof(struct mvebu_spi_priv),
4249985bdb1SStefan Roese 	.probe = mvebu_spi_probe,
4259985bdb1SStefan Roese };
4269985bdb1SStefan Roese #endif
427