spi: omap3: Convert to driver model
After this conversion the driver will able to support both dm and non-dm and code is more extensible like we can remove the non-dm part simply without touching anycode if all the boards which are using this driver become dm driven. Cc: Tom Rini <trini@konsulko.com> Reviewed-by: Simon Glass <sjg@chromium.org> Acked-by: Christophe Ricard <christophe-h.ricard@st.com> Tested-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: Jagan Teki <jteki@openedev.com> [Set priv->wordlen, Add Kconfig entry and file credit for dm conversion] Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
This commit is contained in:
		
							parent
							
								
									03661d85f0
								
							
						
					
					
						commit
						77b8d04854
					
				|  | @ -155,6 +155,13 @@ config ZYNQ_QSPI | |||
| 	  Zynq QSPI IP core. This IP is used to connect the flash in | ||||
| 	  4-bit qspi, 8-bit dual stacked and shared 4-bit dual parallel. | ||||
| 
 | ||||
| config OMAP3_SPI | ||||
| 	bool "McSPI driver for OMAP" | ||||
| 	help | ||||
| 	  SPI master controller for OMAP24XX and later Multichannel SPI | ||||
| 	  (McSPI). This driver be used to access SPI chips on platforms | ||||
| 	  embedding this OMAP3 McSPI IP core. | ||||
| 
 | ||||
| endif # if DM_SPI | ||||
| 
 | ||||
| config FSL_ESPI | ||||
|  |  | |||
|  | @ -1,4 +1,7 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2016 Jagan Teki <jteki@openedev.com> | ||||
|  *		      Christophe Ricard <christophe.ricard@gmail.com> | ||||
|  * | ||||
|  * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com> | ||||
|  * | ||||
|  * Driver for McSPI controller on OMAP3. Based on davinci_spi.c | ||||
|  | @ -15,10 +18,13 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <common.h> | ||||
| #include <dm.h> | ||||
| #include <spi.h> | ||||
| #include <malloc.h> | ||||
| #include <asm/io.h> | ||||
| 
 | ||||
| DECLARE_GLOBAL_DATA_PTR; | ||||
| 
 | ||||
| #if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) | ||||
| #define OMAP3_MCSPI1_BASE	0x48030100 | ||||
| #define OMAP3_MCSPI2_BASE	0x481A0100 | ||||
|  | @ -65,6 +71,8 @@ | |||
| #define OMAP3_MCSPI_CHCTRL_DIS		(0 << 0) | ||||
| 
 | ||||
| #define OMAP3_MCSPI_WAKEUPENABLE_WKEN	BIT(0) | ||||
| #define MCSPI_PINDIR_D0_IN_D1_OUT	0 | ||||
| #define MCSPI_PINDIR_D0_OUT_D1_IN	1 | ||||
| 
 | ||||
| #define OMAP3_MCSPI_MAX_FREQ		48000000 | ||||
| #define SPI_WAIT_TIMEOUT		10 | ||||
|  | @ -94,58 +102,402 @@ struct mcspi { | |||
| 	/* channel3: 0x68 - 0x78, bus 0 */ | ||||
| }; | ||||
| 
 | ||||
| struct omap3_spi_slave { | ||||
| 	struct spi_slave slave; | ||||
| struct omap3_spi_priv { | ||||
| 	struct mcspi *regs; | ||||
| 	unsigned int cs; | ||||
| 	unsigned int freq; | ||||
| 	unsigned int mode; | ||||
| 	unsigned int wordlen; | ||||
| 	unsigned int pin_dir:1; | ||||
| }; | ||||
| 
 | ||||
| static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val) | ||||
| { | ||||
| 	writel(val, &priv->regs->channel[priv->cs].chconf); | ||||
| 	/* Flash post writes to make immediate effect */ | ||||
| 	readl(&priv->regs->channel[priv->cs].chconf); | ||||
| } | ||||
| 
 | ||||
| static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable) | ||||
| { | ||||
| 	writel(enable, &priv->regs->channel[priv->cs].chctrl); | ||||
| 	/* Flash post writes to make immediate effect */ | ||||
| 	readl(&priv->regs->channel[priv->cs].chctrl); | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len, | ||||
| 			   const void *txp, unsigned long flags) | ||||
| { | ||||
| 	ulong start; | ||||
| 	int i, chconf; | ||||
| 
 | ||||
| 	chconf = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 	/* Enable the channel */ | ||||
| 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (priv->wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(priv, chconf); | ||||
| 
 | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		/* wait till TX register is empty (TXS == 1) */ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&priv->regs->channel[priv->cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_TXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI TXS timed out, status=0x%08x\n", | ||||
| 					readl(&priv->regs->channel[priv->cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Write the data */ | ||||
| 		unsigned int *tx = &priv->regs->channel[priv->cs].tx; | ||||
| 		if (priv->wordlen > 16) | ||||
| 			writel(((u32 *)txp)[i], tx); | ||||
| 		else if (priv->wordlen > 8) | ||||
| 			writel(((u16 *)txp)[i], tx); | ||||
| 		else | ||||
| 			writel(((u8 *)txp)[i], tx); | ||||
| 	} | ||||
| 
 | ||||
| 	/* wait to finish of transfer */ | ||||
| 	while ((readl(&priv->regs->channel[priv->cs].chstat) & | ||||
| 			(OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) != | ||||
| 			(OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) | ||||
| 		; | ||||
| 
 | ||||
| 	/* Disable the channel otherwise the next immediate RX will get affected */ | ||||
| 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 
 | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(priv, chconf); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len, | ||||
| 			  void *rxp, unsigned long flags) | ||||
| { | ||||
| 	int i, chconf; | ||||
| 	ulong start; | ||||
| 
 | ||||
| 	chconf = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 	/* Enable the channel */ | ||||
| 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (priv->wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(priv, chconf); | ||||
| 
 | ||||
| 	writel(0, &priv->regs->channel[priv->cs].tx); | ||||
| 
 | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		start = get_timer(0); | ||||
| 		/* Wait till RX register contains data (RXS == 1) */ | ||||
| 		while (!(readl(&priv->regs->channel[priv->cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_RXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI RXS timed out, status=0x%08x\n", | ||||
| 					readl(&priv->regs->channel[priv->cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Disable the channel to prevent furher receiving */ | ||||
| 		if (i == (len - 1)) | ||||
| 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 		/* Read the data */ | ||||
| 		unsigned int *rx = &priv->regs->channel[priv->cs].rx; | ||||
| 		if (priv->wordlen > 16) | ||||
| 			((u32 *)rxp)[i] = readl(rx); | ||||
| 		else if (priv->wordlen > 8) | ||||
| 			((u16 *)rxp)[i] = (u16)readl(rx); | ||||
| 		else | ||||
| 			((u8 *)rxp)[i] = (u8)readl(rx); | ||||
| 	} | ||||
| 
 | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(priv, chconf); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*McSPI Transmit Receive Mode*/ | ||||
| static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len, | ||||
| 			  const void *txp, void *rxp, unsigned long flags) | ||||
| { | ||||
| 	ulong start; | ||||
| 	int chconf, i = 0; | ||||
| 
 | ||||
| 	chconf = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 	/*Enable SPI channel*/ | ||||
| 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	/*set TRANSMIT-RECEIVE Mode*/ | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (priv->wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(priv, chconf); | ||||
| 
 | ||||
| 	/*Shift in and out 1 byte at time*/ | ||||
| 	for (i=0; i < len; i++){ | ||||
| 		/* Write: wait for TX empty (TXS == 1)*/ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&priv->regs->channel[priv->cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_TXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI TXS timed out, status=0x%08x\n", | ||||
| 					readl(&priv->regs->channel[priv->cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Write the data */ | ||||
| 		unsigned int *tx = &priv->regs->channel[priv->cs].tx; | ||||
| 		if (priv->wordlen > 16) | ||||
| 			writel(((u32 *)txp)[i], tx); | ||||
| 		else if (priv->wordlen > 8) | ||||
| 			writel(((u16 *)txp)[i], tx); | ||||
| 		else | ||||
| 			writel(((u8 *)txp)[i], tx); | ||||
| 
 | ||||
| 		/*Read: wait for RX containing data (RXS == 1)*/ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&priv->regs->channel[priv->cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_RXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI RXS timed out, status=0x%08x\n", | ||||
| 					readl(&priv->regs->channel[priv->cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Read the data */ | ||||
| 		unsigned int *rx = &priv->regs->channel[priv->cs].rx; | ||||
| 		if (priv->wordlen > 16) | ||||
| 			((u32 *)rxp)[i] = readl(rx); | ||||
| 		else if (priv->wordlen > 8) | ||||
| 			((u16 *)rxp)[i] = (u16)readl(rx); | ||||
| 		else | ||||
| 			((u8 *)rxp)[i] = (u8)readl(rx); | ||||
| 	} | ||||
| 	/* Disable the channel */ | ||||
| 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 	/*if transfer must be terminated disable the channel*/ | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(priv, chconf); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen, | ||||
| 		     const void *dout, void *din, unsigned long flags) | ||||
| { | ||||
| 	unsigned int	len; | ||||
| 	int ret = -1; | ||||
| 
 | ||||
| 	if (priv->wordlen < 4 || priv->wordlen > 32) { | ||||
| 		printf("omap3_spi: invalid wordlen %d\n", priv->wordlen); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (bitlen % priv->wordlen) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	len = bitlen / priv->wordlen; | ||||
| 
 | ||||
| 	if (bitlen == 0) {	 /* only change CS */ | ||||
| 		int chconf = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 		if (flags & SPI_XFER_BEGIN) { | ||||
| 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | ||||
| 			chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 			omap3_spi_write_chconf(priv, chconf); | ||||
| 		} | ||||
| 		if (flags & SPI_XFER_END) { | ||||
| 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 			omap3_spi_write_chconf(priv, chconf); | ||||
| 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 		} | ||||
| 		ret = 0; | ||||
| 	} else { | ||||
| 		if (dout != NULL && din != NULL) | ||||
| 			ret = omap3_spi_txrx(priv, len, dout, din, flags); | ||||
| 		else if (dout != NULL) | ||||
| 			ret = omap3_spi_write(priv, len, dout, flags); | ||||
| 		else if (din != NULL) | ||||
| 			ret = omap3_spi_read(priv, len, din, flags); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void _omap3_spi_set_speed(struct omap3_spi_priv *priv) | ||||
| { | ||||
| 	uint32_t confr, div = 0; | ||||
| 
 | ||||
| 	confr = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ | ||||
| 	if (priv->freq) { | ||||
| 		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) | ||||
| 					> priv->freq) | ||||
| 			div++; | ||||
| 	} else { | ||||
| 		 div = 0xC; | ||||
| 	} | ||||
| 
 | ||||
| 	/* set clock divisor */ | ||||
| 	confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; | ||||
| 	confr |= div << 2; | ||||
| 
 | ||||
| 	omap3_spi_write_chconf(priv, confr); | ||||
| } | ||||
| 
 | ||||
| static void _omap3_spi_set_mode(struct omap3_spi_priv *priv) | ||||
| { | ||||
| 	uint32_t confr; | ||||
| 
 | ||||
| 	confr = readl(&priv->regs->channel[priv->cs].chconf); | ||||
| 
 | ||||
| 	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
 | ||||
| 	 * REVISIT: this controller could support SPI_3WIRE mode. | ||||
| 	 */ | ||||
| 	if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { | ||||
| 		confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); | ||||
| 		confr |= OMAP3_MCSPI_CHCONF_DPE0; | ||||
| 	} else { | ||||
| 		confr &= ~OMAP3_MCSPI_CHCONF_DPE0; | ||||
| 		confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* set SPI mode 0..3 */ | ||||
| 	confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA); | ||||
| 	if (priv->mode & SPI_CPHA) | ||||
| 		confr |= OMAP3_MCSPI_CHCONF_PHA; | ||||
| 	if (priv->mode & SPI_CPOL) | ||||
| 		confr |= OMAP3_MCSPI_CHCONF_POL; | ||||
| 
 | ||||
| 	/* set chipselect polarity; manage with FORCE */ | ||||
| 	if (!(priv->mode & SPI_CS_HIGH)) | ||||
| 		confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ | ||||
| 	else | ||||
| 		confr &= ~OMAP3_MCSPI_CHCONF_EPOL; | ||||
| 
 | ||||
| 	/* Transmit & receive mode */ | ||||
| 	confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; | ||||
| 
 | ||||
| 	omap3_spi_write_chconf(priv, confr); | ||||
| } | ||||
| 
 | ||||
| static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) | ||||
| { | ||||
| 	unsigned int confr; | ||||
| 
 | ||||
| 	/* McSPI individual channel configuration */ | ||||
| 	confr = readl(&priv->regs->channel[priv->wordlen].chconf); | ||||
| 
 | ||||
| 	/* wordlength */ | ||||
| 	confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK; | ||||
| 	confr |= (priv->wordlen - 1) << 7; | ||||
| 
 | ||||
| 	omap3_spi_write_chconf(priv, confr); | ||||
| } | ||||
| 
 | ||||
| static void spi_reset(struct mcspi *regs) | ||||
| { | ||||
| 	unsigned int tmp; | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, ®s->sysconfig); | ||||
| 	do { | ||||
| 		tmp = readl(®s->sysstatus); | ||||
| 	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | | ||||
| 	       OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | | ||||
| 	       OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, ®s->sysconfig); | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, ®s->wakeupenable); | ||||
| } | ||||
| 
 | ||||
| static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv) | ||||
| { | ||||
| 	unsigned int conf; | ||||
| 
 | ||||
| 	spi_reset(priv->regs); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * setup when switching from (reset default) slave mode | ||||
| 	 * to single-channel master mode | ||||
| 	 */ | ||||
| 	conf = readl(&priv->regs->modulctrl); | ||||
| 	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); | ||||
| 	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; | ||||
| 
 | ||||
| 	writel(conf, &priv->regs->modulctrl); | ||||
| 
 | ||||
| 	_omap3_spi_set_mode(priv); | ||||
| 	_omap3_spi_set_speed(priv); | ||||
| } | ||||
| 
 | ||||
| #ifndef CONFIG_DM_SPI | ||||
| 
 | ||||
| struct omap3_spi_slave { | ||||
| 	struct spi_slave	 slave; | ||||
| 	struct omap3_spi_priv   spi_priv; | ||||
| }; | ||||
| 
 | ||||
| struct omap3_spi_priv *priv; | ||||
| 
 | ||||
| static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) | ||||
| { | ||||
| 	return container_of(slave, struct omap3_spi_slave, slave); | ||||
| } | ||||
| 
 | ||||
| static void spi_reset(struct omap3_spi_slave *ds) | ||||
| { | ||||
| 	unsigned int tmp; | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig); | ||||
| 	do { | ||||
| 		tmp = readl(&ds->regs->sysstatus); | ||||
| 	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | | ||||
| 				 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | | ||||
| 				 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, | ||||
| 				 &ds->regs->sysconfig); | ||||
| 
 | ||||
| 	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable); | ||||
| } | ||||
| 
 | ||||
| static void omap3_spi_write_chconf(struct omap3_spi_slave *ds, int val) | ||||
| { | ||||
| 	writel(val, &ds->regs->channel[ds->slave.cs].chconf); | ||||
| 	/* Flash post writes to make immediate effect */ | ||||
| 	readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| } | ||||
| 
 | ||||
| static void omap3_spi_set_enable(struct omap3_spi_slave *ds, int enable) | ||||
| { | ||||
| 	writel(enable, &ds->regs->channel[ds->slave.cs].chctrl); | ||||
| 	/* Flash post writes to make immediate effect */ | ||||
| 	readl(&ds->regs->channel[ds->slave.cs].chctrl); | ||||
| } | ||||
| 
 | ||||
| void spi_init() | ||||
| void spi_init(void) | ||||
| { | ||||
| 	/* do nothing */ | ||||
| } | ||||
| 
 | ||||
| struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | ||||
| 				  unsigned int max_hz, unsigned int mode) | ||||
| void spi_free_slave(struct spi_slave *slave) | ||||
| { | ||||
| 	struct omap3_spi_slave	*ds; | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 
 | ||||
| 	free(ds); | ||||
| } | ||||
| 
 | ||||
| int spi_claim_bus(struct spi_slave *slave) | ||||
| { | ||||
| 	_omap3_spi_claim_bus(priv); | ||||
| 	_omap3_spi_set_wordlen(priv); | ||||
| 	_omap3_spi_set_mode(priv); | ||||
| 	_omap3_spi_set_speed(priv); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void spi_release_bus(struct spi_slave *slave) | ||||
| { | ||||
| 	/* Reset the SPI hardware */ | ||||
| 	spi_reset(priv->regs); | ||||
| } | ||||
| 
 | ||||
| struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | ||||
| 				     unsigned int max_hz, unsigned int mode) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds; | ||||
| 	struct mcspi *regs; | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -159,41 +511,38 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |||
| 
 | ||||
| 	switch (bus) { | ||||
| 	case 0: | ||||
| 		regs = (struct mcspi *)OMAP3_MCSPI1_BASE; | ||||
| 		break; | ||||
| 		 regs = (struct mcspi *)OMAP3_MCSPI1_BASE; | ||||
| 		 break; | ||||
| #ifdef OMAP3_MCSPI2_BASE | ||||
| 	case 1: | ||||
| 		regs = (struct mcspi *)OMAP3_MCSPI2_BASE; | ||||
| 		break; | ||||
| 		 regs = (struct mcspi *)OMAP3_MCSPI2_BASE; | ||||
| 		 break; | ||||
| #endif | ||||
| #ifdef OMAP3_MCSPI3_BASE | ||||
| 	case 2: | ||||
| 		regs = (struct mcspi *)OMAP3_MCSPI3_BASE; | ||||
| 		break; | ||||
| 		 regs = (struct mcspi *)OMAP3_MCSPI3_BASE; | ||||
| 		 break; | ||||
| #endif | ||||
| #ifdef OMAP3_MCSPI4_BASE | ||||
| 	case 3: | ||||
| 		regs = (struct mcspi *)OMAP3_MCSPI4_BASE; | ||||
| 		break; | ||||
| 		 regs = (struct mcspi *)OMAP3_MCSPI4_BASE; | ||||
| 		 break; | ||||
| #endif | ||||
| 	default: | ||||
| 		printf("SPI error: unsupported bus %i. \
 | ||||
| 			Supported busses 0 - 3\n", bus); | ||||
| 		return NULL; | ||||
| 		 printf("SPI error: unsupported bus %i.  Supported busses 0 - 3\n", bus); | ||||
| 		 return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (((bus == 0) && (cs > 3)) || | ||||
| 			((bus == 1) && (cs > 1)) || | ||||
| 			((bus == 2) && (cs > 1)) || | ||||
| 			((bus == 3) && (cs > 0))) { | ||||
| 		printf("SPI error: unsupported chip select %i \
 | ||||
| 			on bus %i\n", cs, bus); | ||||
| 	    ((bus == 1) && (cs > 1)) || | ||||
| 	    ((bus == 2) && (cs > 1)) || | ||||
| 	    ((bus == 3) && (cs > 0))) { | ||||
| 		printf("SPI error: unsupported chip select %i on bus %i\n", cs, bus); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (max_hz > OMAP3_MCSPI_MAX_FREQ) { | ||||
| 		printf("SPI error: unsupported frequency %i Hz. \
 | ||||
| 			Max frequency is 48 Mhz\n", max_hz); | ||||
| 		printf("SPI error: unsupported frequency %i Hz. Max frequency is 48 Mhz\n", max_hz); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -208,332 +557,122 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | |||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	ds->regs = regs; | ||||
| 	ds->freq = max_hz; | ||||
| 	ds->mode = mode; | ||||
| 	priv = &ds->spi_priv; | ||||
| 
 | ||||
| 	priv->regs = regs; | ||||
| 	priv->cs = cs; | ||||
| 	priv->freq = max_hz; | ||||
| 	priv->mode = mode; | ||||
| 	priv->wordlen = ds->slave.wordlen; | ||||
| #ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED | ||||
| 	priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; | ||||
| #endif | ||||
| 
 | ||||
| 	return &ds->slave; | ||||
| } | ||||
| 
 | ||||
| void spi_free_slave(struct spi_slave *slave) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 
 | ||||
| 	free(ds); | ||||
| } | ||||
| 
 | ||||
| int spi_claim_bus(struct spi_slave *slave) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 	unsigned int conf, div = 0; | ||||
| 
 | ||||
| 	/* McSPI global module configuration */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * setup when switching from (reset default) slave mode | ||||
| 	 * to single-channel master mode | ||||
| 	 */ | ||||
| 	spi_reset(ds); | ||||
| 	conf = readl(&ds->regs->modulctrl); | ||||
| 	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); | ||||
| 	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; | ||||
| 	writel(conf, &ds->regs->modulctrl); | ||||
| 
 | ||||
| 	/* McSPI individual channel configuration */ | ||||
| 
 | ||||
| 	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ | ||||
| 	if (ds->freq) { | ||||
| 		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) | ||||
| 					 > ds->freq) | ||||
| 			div++; | ||||
| 	} else | ||||
| 		div = 0xC; | ||||
| 
 | ||||
| 	conf = readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| 
 | ||||
| 	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
 | ||||
| 	 * REVISIT: this controller could support SPI_3WIRE mode. | ||||
| 	 */ | ||||
| #ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED | ||||
| 	/*
 | ||||
| 	 * Some boards have D0 wired as MOSI / D1 as MISO instead of | ||||
| 	 * The normal D0 as MISO / D1 as MOSI. | ||||
| 	 */ | ||||
| 	conf &= ~OMAP3_MCSPI_CHCONF_DPE0; | ||||
| 	conf |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1; | ||||
| #else | ||||
| 	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); | ||||
| 	conf |= OMAP3_MCSPI_CHCONF_DPE0; | ||||
| #endif | ||||
| 
 | ||||
| 	/* wordlength */ | ||||
| 	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; | ||||
| 	conf |= (ds->slave.wordlen - 1) << 7; | ||||
| 
 | ||||
| 	/* set chipselect polarity; manage with FORCE */ | ||||
| 	if (!(ds->mode & SPI_CS_HIGH)) | ||||
| 		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ | ||||
| 	else | ||||
| 		conf &= ~OMAP3_MCSPI_CHCONF_EPOL; | ||||
| 
 | ||||
| 	/* set clock divisor */ | ||||
| 	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; | ||||
| 	conf |= div << 2; | ||||
| 
 | ||||
| 	/* set SPI mode 0..3 */ | ||||
| 	if (ds->mode & SPI_CPOL) | ||||
| 		conf |= OMAP3_MCSPI_CHCONF_POL; | ||||
| 	else | ||||
| 		conf &= ~OMAP3_MCSPI_CHCONF_POL; | ||||
| 	if (ds->mode & SPI_CPHA) | ||||
| 		conf |= OMAP3_MCSPI_CHCONF_PHA; | ||||
| 	else | ||||
| 		conf &= ~OMAP3_MCSPI_CHCONF_PHA; | ||||
| 
 | ||||
| 	/* Transmit & receive mode */ | ||||
| 	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; | ||||
| 
 | ||||
| 	omap3_spi_write_chconf(ds,conf); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void spi_release_bus(struct spi_slave *slave) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 
 | ||||
| 	/* Reset the SPI hardware */ | ||||
| 	spi_reset(ds); | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_write(struct spi_slave *slave, unsigned int len, | ||||
| 			   const void *txp, unsigned long flags) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 	int i; | ||||
| 	ulong start; | ||||
| 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| 
 | ||||
| 	/* Enable the channel */ | ||||
| 	omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (ds->slave.wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(ds,chconf); | ||||
| 
 | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		/* wait till TX register is empty (TXS == 1) */ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_TXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI TXS timed out, status=0x%08x\n", | ||||
| 				       readl(&ds->regs->channel[ds->slave.cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Write the data */ | ||||
| 		unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; | ||||
| 		if (ds->slave.wordlen > 16) | ||||
| 			writel(((u32 *)txp)[i], tx); | ||||
| 		else if (ds->slave.wordlen > 8) | ||||
| 			writel(((u16 *)txp)[i], tx); | ||||
| 		else | ||||
| 			writel(((u8 *)txp)[i], tx); | ||||
| 	} | ||||
| 
 | ||||
| 	/* wait to finish of transfer */ | ||||
| 	while ((readl(&ds->regs->channel[ds->slave.cs].chstat) & | ||||
| 			 (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) != | ||||
| 			 (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)); | ||||
| 
 | ||||
| 	/* Disable the channel otherwise the next immediate RX will get affected */ | ||||
| 	omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 
 | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(ds,chconf); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_read(struct spi_slave *slave, unsigned int len, | ||||
| 			  void *rxp, unsigned long flags) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 	int i; | ||||
| 	ulong start; | ||||
| 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| 
 | ||||
| 	/* Enable the channel */ | ||||
| 	omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (ds->slave.wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(ds,chconf); | ||||
| 
 | ||||
| 	writel(0, &ds->regs->channel[ds->slave.cs].tx); | ||||
| 
 | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		start = get_timer(0); | ||||
| 		/* Wait till RX register contains data (RXS == 1) */ | ||||
| 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_RXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI RXS timed out, status=0x%08x\n", | ||||
| 				       readl(&ds->regs->channel[ds->slave.cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/* Disable the channel to prevent furher receiving */ | ||||
| 		if(i == (len - 1)) | ||||
| 			omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 		/* Read the data */ | ||||
| 		unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; | ||||
| 		if (ds->slave.wordlen > 16) | ||||
| 			((u32 *)rxp)[i] = readl(rx); | ||||
| 		else if (ds->slave.wordlen > 8) | ||||
| 			((u16 *)rxp)[i] = (u16)readl(rx); | ||||
| 		else | ||||
| 			((u8 *)rxp)[i] = (u8)readl(rx); | ||||
| 	} | ||||
| 
 | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(ds,chconf); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*McSPI Transmit Receive Mode*/ | ||||
| static int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, | ||||
| 			  const void *txp, void *rxp, unsigned long flags) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 	ulong start; | ||||
| 	int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| 	int i=0; | ||||
| 
 | ||||
| 	/*Enable SPI channel*/ | ||||
| 	omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); | ||||
| 
 | ||||
| 	/*set TRANSMIT-RECEIVE Mode*/ | ||||
| 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | ||||
| 	chconf |= (ds->slave.wordlen - 1) << 7; | ||||
| 	chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 	omap3_spi_write_chconf(ds,chconf); | ||||
| 
 | ||||
| 	/*Shift in and out 1 byte at time*/ | ||||
| 	for (i=0; i < len; i++){ | ||||
| 		/* Write: wait for TX empty (TXS == 1)*/ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_TXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI TXS timed out, status=0x%08x\n", | ||||
| 				       readl(&ds->regs->channel[ds->slave.cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Write the data */ | ||||
| 		unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; | ||||
| 		if (ds->slave.wordlen > 16) | ||||
| 			writel(((u32 *)txp)[i], tx); | ||||
| 		else if (ds->slave.wordlen > 8) | ||||
| 			writel(((u16 *)txp)[i], tx); | ||||
| 		else | ||||
| 			writel(((u8 *)txp)[i], tx); | ||||
| 
 | ||||
| 		/*Read: wait for RX containing data (RXS == 1)*/ | ||||
| 		start = get_timer(0); | ||||
| 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & | ||||
| 			 OMAP3_MCSPI_CHSTAT_RXS)) { | ||||
| 			if (get_timer(start) > SPI_WAIT_TIMEOUT) { | ||||
| 				printf("SPI RXS timed out, status=0x%08x\n", | ||||
| 				       readl(&ds->regs->channel[ds->slave.cs].chstat)); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 		/* Read the data */ | ||||
| 		unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; | ||||
| 		if (ds->slave.wordlen > 16) | ||||
| 			((u32 *)rxp)[i] = readl(rx); | ||||
| 		else if (ds->slave.wordlen > 8) | ||||
| 			((u16 *)rxp)[i] = (u16)readl(rx); | ||||
| 		else | ||||
| 			((u8 *)rxp)[i] = (u8)readl(rx); | ||||
| 	} | ||||
| 	/* Disable the channel */ | ||||
| 	omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 
 | ||||
| 	/*if transfer must be terminated disable the channel*/ | ||||
| 	if (flags & SPI_XFER_END) { | ||||
| 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 		omap3_spi_write_chconf(ds,chconf); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | ||||
| 	     const void *dout, void *din, unsigned long flags) | ||||
| { return _spi_xfer(priv, bitlen, dout, din, flags); } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static int omap3_spi_claim_bus(struct udevice *dev) | ||||
| { | ||||
| 	struct omap3_spi_slave *ds = to_omap3_spi(slave); | ||||
| 	unsigned int	len; | ||||
| 	int ret = -1; | ||||
| 	struct udevice *bus = dev->parent; | ||||
| 	struct omap3_spi_priv *priv = dev_get_priv(bus); | ||||
| 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | ||||
| 
 | ||||
| 	if (ds->slave.wordlen < 4 || ds->slave.wordlen > 32) { | ||||
| 		printf("omap3_spi: invalid wordlen %d\n", ds->slave.wordlen); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	priv->cs = slave_plat->cs; | ||||
| 	priv->mode = slave_plat->mode; | ||||
| 	priv->freq = slave_plat->max_hz; | ||||
| 	_omap3_spi_claim_bus(priv); | ||||
| 
 | ||||
| 	if (bitlen % ds->slave.wordlen) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	len = bitlen / ds->slave.wordlen; | ||||
| 
 | ||||
| 	if (bitlen == 0) {	 /* only change CS */ | ||||
| 		int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); | ||||
| 
 | ||||
| 		if (flags & SPI_XFER_BEGIN) { | ||||
| 			omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); | ||||
| 			chconf |= OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 			omap3_spi_write_chconf(ds,chconf); | ||||
| 		} | ||||
| 		if (flags & SPI_XFER_END) { | ||||
| 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | ||||
| 			omap3_spi_write_chconf(ds,chconf); | ||||
| 			omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); | ||||
| 		} | ||||
| 		ret = 0; | ||||
| 	} else { | ||||
| 		if (dout != NULL && din != NULL) | ||||
| 			ret = omap3_spi_txrx(slave, len, dout, din, flags); | ||||
| 		else if (dout != NULL) | ||||
| 			ret = omap3_spi_write(slave, len, dout, flags); | ||||
| 		else if (din != NULL) | ||||
| 			ret = omap3_spi_read(slave, len, din, flags); | ||||
| 	} | ||||
| 	return ret; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int spi_cs_is_valid(unsigned int bus, unsigned int cs) | ||||
| static int omap3_spi_release_bus(struct udevice *dev) | ||||
| { | ||||
| 	return 1; | ||||
| 	struct udevice *bus = dev->parent; | ||||
| 	struct omap3_spi_priv *priv = dev_get_priv(bus); | ||||
| 
 | ||||
| 	/* Reset the SPI hardware */ | ||||
| 	spi_reset(priv->regs); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void spi_cs_activate(struct spi_slave *slave) | ||||
| static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) | ||||
| { | ||||
| 	struct udevice *bus = dev->parent; | ||||
| 	struct omap3_spi_priv *priv = dev_get_priv(bus); | ||||
| 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | ||||
| 
 | ||||
| 	priv->cs = slave_plat->cs; | ||||
| 	priv->wordlen = wordlen; | ||||
| 	_omap3_spi_set_wordlen(priv); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void spi_cs_deactivate(struct spi_slave *slave) | ||||
| static int omap3_spi_probe(struct udevice *dev) | ||||
| { | ||||
| 	struct omap3_spi_priv *priv = dev_get_priv(dev); | ||||
| 	const void *blob = gd->fdt_blob; | ||||
| 	int node = dev->of_offset; | ||||
| 
 | ||||
| 	priv->regs = (struct mcspi *)dev_get_addr(dev); | ||||
| 	priv->pin_dir = fdtdec_get_uint(blob, node, "ti,pindir-d0-out-d1-in", | ||||
| 					    MCSPI_PINDIR_D0_IN_D1_OUT); | ||||
| 	priv->wordlen = SPI_DEFAULT_WORDLEN; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen, | ||||
| 			    const void *dout, void *din, unsigned long flags) | ||||
| { | ||||
| 	struct udevice *bus = dev->parent; | ||||
| 	struct omap3_spi_priv *priv = dev_get_priv(bus); | ||||
| 
 | ||||
| 	return _spi_xfer(priv, bitlen, dout, din, flags); | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_set_speed(struct udevice *bus, unsigned int speed) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int omap3_spi_set_mode(struct udevice *bus, uint mode) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct dm_spi_ops omap3_spi_ops = { | ||||
| 	.claim_bus      = omap3_spi_claim_bus, | ||||
| 	.release_bus    = omap3_spi_release_bus, | ||||
| 	.set_wordlen    = omap3_spi_set_wordlen, | ||||
| 	.xfer	    = omap3_spi_xfer, | ||||
| 	.set_speed      = omap3_spi_set_speed, | ||||
| 	.set_mode	= omap3_spi_set_mode, | ||||
| 	/*
 | ||||
| 	 * cs_info is not needed, since we require all chip selects to be | ||||
| 	 * in the device tree explicitly | ||||
| 	 */ | ||||
| }; | ||||
| 
 | ||||
| static const struct udevice_id omap3_spi_ids[] = { | ||||
| 	{ .compatible = "ti,omap2-mcspi" }, | ||||
| 	{ .compatible = "ti,omap4-mcspi" }, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| U_BOOT_DRIVER(omap3_spi) = { | ||||
| 	.name   = "omap3_spi", | ||||
| 	.id     = UCLASS_SPI, | ||||
| 	.of_match = omap3_spi_ids, | ||||
| 	.probe = omap3_spi_probe, | ||||
| 	.ops    = &omap3_spi_ops, | ||||
| 	.priv_auto_alloc_size = sizeof(struct omap3_spi_priv), | ||||
| 	.probe = omap3_spi_probe, | ||||
| }; | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue