xref: /rk3399_rockchip-uboot/drivers/spi/omap3_spi.c (revision cafc69117ec0b551390dae9baf2f9cb1124b56c9)
153736baaSDirk Behme /*
277b8d048SJagan Teki  * Copyright (C) 2016 Jagan Teki <jteki@openedev.com>
377b8d048SJagan Teki  *		      Christophe Ricard <christophe.ricard@gmail.com>
477b8d048SJagan Teki  *
553736baaSDirk Behme  * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
653736baaSDirk Behme  *
753736baaSDirk Behme  * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
853736baaSDirk Behme  * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
953736baaSDirk Behme  *
1053736baaSDirk Behme  * Copyright (C) 2007 Atmel Corporation
1153736baaSDirk Behme  *
1253736baaSDirk Behme  * Parts taken from linux/drivers/spi/omap2_mcspi.c
1353736baaSDirk Behme  * Copyright (C) 2005, 2006 Nokia Corporation
1453736baaSDirk Behme  *
1553736baaSDirk Behme  * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com>
1653736baaSDirk Behme  *
171a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
1853736baaSDirk Behme  */
1953736baaSDirk Behme 
2053736baaSDirk Behme #include <common.h>
2177b8d048SJagan Teki #include <dm.h>
2253736baaSDirk Behme #include <spi.h>
2353736baaSDirk Behme #include <malloc.h>
2453736baaSDirk Behme #include <asm/io.h>
2553736baaSDirk Behme 
2677b8d048SJagan Teki DECLARE_GLOBAL_DATA_PTR;
2777b8d048SJagan Teki 
28682c1723SJagan Teki #if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
29682c1723SJagan Teki #define OMAP3_MCSPI1_BASE	0x48030100
30682c1723SJagan Teki #define OMAP3_MCSPI2_BASE	0x481A0100
31682c1723SJagan Teki #else
32682c1723SJagan Teki #define OMAP3_MCSPI1_BASE	0x48098000
33682c1723SJagan Teki #define OMAP3_MCSPI2_BASE	0x4809A000
34682c1723SJagan Teki #define OMAP3_MCSPI3_BASE	0x480B8000
35682c1723SJagan Teki #define OMAP3_MCSPI4_BASE	0x480BA000
36682c1723SJagan Teki #endif
37682c1723SJagan Teki 
385f89a15eSMartin Hejnfelt #define OMAP4_MCSPI_REG_OFFSET	0x100
395f89a15eSMartin Hejnfelt 
405f89a15eSMartin Hejnfelt struct omap2_mcspi_platform_config {
415f89a15eSMartin Hejnfelt 	unsigned int regs_offset;
425f89a15eSMartin Hejnfelt };
435f89a15eSMartin Hejnfelt 
44682c1723SJagan Teki /* per-register bitmasks */
45682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
46682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
47682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE	BIT(0)
48682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1)
49682c1723SJagan Teki 
50682c1723SJagan Teki #define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0)
51682c1723SJagan Teki 
52682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_SINGLE	BIT(0)
53682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_MS	BIT(2)
54682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_STEST	BIT(3)
55682c1723SJagan Teki 
56682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_PHA		BIT(0)
57682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_POL		BIT(1)
58682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_CLKD_MASK	GENMASK(5, 2)
59682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_EPOL		BIT(6)
60682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_WL_MASK	GENMASK(11, 7)
61682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
62682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
63682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_MASK	GENMASK(13, 12)
64682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DMAW		BIT(14)
65682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DMAR		BIT(15)
66682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DPE0		BIT(16)
67682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DPE1		BIT(17)
68682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_IS		BIT(18)
69682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TURBO	BIT(19)
70682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_FORCE	BIT(20)
71682c1723SJagan Teki 
72682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_RXS		BIT(0)
73682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_TXS		BIT(1)
74682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_EOT		BIT(2)
75682c1723SJagan Teki 
76682c1723SJagan Teki #define OMAP3_MCSPI_CHCTRL_EN		BIT(0)
77682c1723SJagan Teki #define OMAP3_MCSPI_CHCTRL_DIS		(0 << 0)
78682c1723SJagan Teki 
79682c1723SJagan Teki #define OMAP3_MCSPI_WAKEUPENABLE_WKEN	BIT(0)
8077b8d048SJagan Teki #define MCSPI_PINDIR_D0_IN_D1_OUT	0
8177b8d048SJagan Teki #define MCSPI_PINDIR_D0_OUT_D1_IN	1
82682c1723SJagan Teki 
83682c1723SJagan Teki #define OMAP3_MCSPI_MAX_FREQ		48000000
84611c9ba2SDavid Dueck #define SPI_WAIT_TIMEOUT		10
8553736baaSDirk Behme 
86682c1723SJagan Teki /* OMAP3 McSPI registers */
87682c1723SJagan Teki struct mcspi_channel {
88682c1723SJagan Teki 	unsigned int chconf;		/* 0x2C, 0x40, 0x54, 0x68 */
89682c1723SJagan Teki 	unsigned int chstat;		/* 0x30, 0x44, 0x58, 0x6C */
90682c1723SJagan Teki 	unsigned int chctrl;		/* 0x34, 0x48, 0x5C, 0x70 */
91682c1723SJagan Teki 	unsigned int tx;		/* 0x38, 0x4C, 0x60, 0x74 */
92682c1723SJagan Teki 	unsigned int rx;		/* 0x3C, 0x50, 0x64, 0x78 */
93682c1723SJagan Teki };
94682c1723SJagan Teki 
95682c1723SJagan Teki struct mcspi {
96682c1723SJagan Teki 	unsigned char res1[0x10];
97682c1723SJagan Teki 	unsigned int sysconfig;		/* 0x10 */
98682c1723SJagan Teki 	unsigned int sysstatus;		/* 0x14 */
99682c1723SJagan Teki 	unsigned int irqstatus;		/* 0x18 */
100682c1723SJagan Teki 	unsigned int irqenable;		/* 0x1C */
101682c1723SJagan Teki 	unsigned int wakeupenable;	/* 0x20 */
102682c1723SJagan Teki 	unsigned int syst;		/* 0x24 */
103682c1723SJagan Teki 	unsigned int modulctrl;		/* 0x28 */
104682c1723SJagan Teki 	struct mcspi_channel channel[4];
105682c1723SJagan Teki 	/* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */
106682c1723SJagan Teki 	/* channel1: 0x40 - 0x50, bus 0 & 1 */
107682c1723SJagan Teki 	/* channel2: 0x54 - 0x64, bus 0 & 1 */
108682c1723SJagan Teki 	/* channel3: 0x68 - 0x78, bus 0 */
109682c1723SJagan Teki };
110682c1723SJagan Teki 
11177b8d048SJagan Teki struct omap3_spi_priv {
11241bccb81SJagan Teki #ifndef CONFIG_DM_SPI
11341bccb81SJagan Teki 	struct spi_slave slave;
11441bccb81SJagan Teki #endif
115682c1723SJagan Teki 	struct mcspi *regs;
11677b8d048SJagan Teki 	unsigned int cs;
117682c1723SJagan Teki 	unsigned int freq;
118682c1723SJagan Teki 	unsigned int mode;
11977b8d048SJagan Teki 	unsigned int wordlen;
12077b8d048SJagan Teki 	unsigned int pin_dir:1;
121682c1723SJagan Teki };
122682c1723SJagan Teki 
omap3_spi_write_chconf(struct omap3_spi_priv * priv,int val)12377b8d048SJagan Teki static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val)
12477b8d048SJagan Teki {
12577b8d048SJagan Teki 	writel(val, &priv->regs->channel[priv->cs].chconf);
12677b8d048SJagan Teki 	/* Flash post writes to make immediate effect */
12777b8d048SJagan Teki 	readl(&priv->regs->channel[priv->cs].chconf);
12877b8d048SJagan Teki }
12977b8d048SJagan Teki 
omap3_spi_set_enable(struct omap3_spi_priv * priv,int enable)13077b8d048SJagan Teki static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable)
13177b8d048SJagan Teki {
13277b8d048SJagan Teki 	writel(enable, &priv->regs->channel[priv->cs].chctrl);
13377b8d048SJagan Teki 	/* Flash post writes to make immediate effect */
13477b8d048SJagan Teki 	readl(&priv->regs->channel[priv->cs].chctrl);
13577b8d048SJagan Teki }
13677b8d048SJagan Teki 
omap3_spi_write(struct omap3_spi_priv * priv,unsigned int len,const void * txp,unsigned long flags)13777b8d048SJagan Teki static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len,
13877b8d048SJagan Teki 			   const void *txp, unsigned long flags)
13977b8d048SJagan Teki {
14077b8d048SJagan Teki 	ulong start;
14177b8d048SJagan Teki 	int i, chconf;
14277b8d048SJagan Teki 
14377b8d048SJagan Teki 	chconf = readl(&priv->regs->channel[priv->cs].chconf);
14477b8d048SJagan Teki 
14577b8d048SJagan Teki 	/* Enable the channel */
14677b8d048SJagan Teki 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
14777b8d048SJagan Teki 
14877b8d048SJagan Teki 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
14977b8d048SJagan Teki 	chconf |= (priv->wordlen - 1) << 7;
15077b8d048SJagan Teki 	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
15177b8d048SJagan Teki 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
15277b8d048SJagan Teki 	omap3_spi_write_chconf(priv, chconf);
15377b8d048SJagan Teki 
15477b8d048SJagan Teki 	for (i = 0; i < len; i++) {
15577b8d048SJagan Teki 		/* wait till TX register is empty (TXS == 1) */
15677b8d048SJagan Teki 		start = get_timer(0);
15777b8d048SJagan Teki 		while (!(readl(&priv->regs->channel[priv->cs].chstat) &
15877b8d048SJagan Teki 			 OMAP3_MCSPI_CHSTAT_TXS)) {
15977b8d048SJagan Teki 			if (get_timer(start) > SPI_WAIT_TIMEOUT) {
16077b8d048SJagan Teki 				printf("SPI TXS timed out, status=0x%08x\n",
16177b8d048SJagan Teki 					readl(&priv->regs->channel[priv->cs].chstat));
16277b8d048SJagan Teki 				return -1;
16377b8d048SJagan Teki 			}
16477b8d048SJagan Teki 		}
16577b8d048SJagan Teki 		/* Write the data */
16677b8d048SJagan Teki 		unsigned int *tx = &priv->regs->channel[priv->cs].tx;
16777b8d048SJagan Teki 		if (priv->wordlen > 16)
16877b8d048SJagan Teki 			writel(((u32 *)txp)[i], tx);
16977b8d048SJagan Teki 		else if (priv->wordlen > 8)
17077b8d048SJagan Teki 			writel(((u16 *)txp)[i], tx);
17177b8d048SJagan Teki 		else
17277b8d048SJagan Teki 			writel(((u8 *)txp)[i], tx);
17377b8d048SJagan Teki 	}
17477b8d048SJagan Teki 
17577b8d048SJagan Teki 	/* wait to finish of transfer */
17677b8d048SJagan Teki 	while ((readl(&priv->regs->channel[priv->cs].chstat) &
17777b8d048SJagan Teki 			(OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) !=
17877b8d048SJagan Teki 			(OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS))
17977b8d048SJagan Teki 		;
18077b8d048SJagan Teki 
18177b8d048SJagan Teki 	/* Disable the channel otherwise the next immediate RX will get affected */
18277b8d048SJagan Teki 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
18377b8d048SJagan Teki 
18477b8d048SJagan Teki 	if (flags & SPI_XFER_END) {
18577b8d048SJagan Teki 
18677b8d048SJagan Teki 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
18777b8d048SJagan Teki 		omap3_spi_write_chconf(priv, chconf);
18877b8d048SJagan Teki 	}
18977b8d048SJagan Teki 	return 0;
19077b8d048SJagan Teki }
19177b8d048SJagan Teki 
omap3_spi_read(struct omap3_spi_priv * priv,unsigned int len,void * rxp,unsigned long flags)19277b8d048SJagan Teki static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len,
19377b8d048SJagan Teki 			  void *rxp, unsigned long flags)
19477b8d048SJagan Teki {
19577b8d048SJagan Teki 	int i, chconf;
19677b8d048SJagan Teki 	ulong start;
19777b8d048SJagan Teki 
19877b8d048SJagan Teki 	chconf = readl(&priv->regs->channel[priv->cs].chconf);
19977b8d048SJagan Teki 
20077b8d048SJagan Teki 	/* Enable the channel */
20177b8d048SJagan Teki 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
20277b8d048SJagan Teki 
20377b8d048SJagan Teki 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
20477b8d048SJagan Teki 	chconf |= (priv->wordlen - 1) << 7;
20577b8d048SJagan Teki 	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
20677b8d048SJagan Teki 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
20777b8d048SJagan Teki 	omap3_spi_write_chconf(priv, chconf);
20877b8d048SJagan Teki 
20977b8d048SJagan Teki 	writel(0, &priv->regs->channel[priv->cs].tx);
21077b8d048SJagan Teki 
21177b8d048SJagan Teki 	for (i = 0; i < len; i++) {
21277b8d048SJagan Teki 		start = get_timer(0);
21377b8d048SJagan Teki 		/* Wait till RX register contains data (RXS == 1) */
21477b8d048SJagan Teki 		while (!(readl(&priv->regs->channel[priv->cs].chstat) &
21577b8d048SJagan Teki 			 OMAP3_MCSPI_CHSTAT_RXS)) {
21677b8d048SJagan Teki 			if (get_timer(start) > SPI_WAIT_TIMEOUT) {
21777b8d048SJagan Teki 				printf("SPI RXS timed out, status=0x%08x\n",
21877b8d048SJagan Teki 					readl(&priv->regs->channel[priv->cs].chstat));
21977b8d048SJagan Teki 				return -1;
22077b8d048SJagan Teki 			}
22177b8d048SJagan Teki 		}
22277b8d048SJagan Teki 
22377b8d048SJagan Teki 		/* Disable the channel to prevent furher receiving */
22477b8d048SJagan Teki 		if (i == (len - 1))
22577b8d048SJagan Teki 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
22677b8d048SJagan Teki 
22777b8d048SJagan Teki 		/* Read the data */
22877b8d048SJagan Teki 		unsigned int *rx = &priv->regs->channel[priv->cs].rx;
22977b8d048SJagan Teki 		if (priv->wordlen > 16)
23077b8d048SJagan Teki 			((u32 *)rxp)[i] = readl(rx);
23177b8d048SJagan Teki 		else if (priv->wordlen > 8)
23277b8d048SJagan Teki 			((u16 *)rxp)[i] = (u16)readl(rx);
23377b8d048SJagan Teki 		else
23477b8d048SJagan Teki 			((u8 *)rxp)[i] = (u8)readl(rx);
23577b8d048SJagan Teki 	}
23677b8d048SJagan Teki 
23777b8d048SJagan Teki 	if (flags & SPI_XFER_END) {
23877b8d048SJagan Teki 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
23977b8d048SJagan Teki 		omap3_spi_write_chconf(priv, chconf);
24077b8d048SJagan Teki 	}
24177b8d048SJagan Teki 
24277b8d048SJagan Teki 	return 0;
24377b8d048SJagan Teki }
24477b8d048SJagan Teki 
24577b8d048SJagan Teki /*McSPI Transmit Receive Mode*/
omap3_spi_txrx(struct omap3_spi_priv * priv,unsigned int len,const void * txp,void * rxp,unsigned long flags)24677b8d048SJagan Teki static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len,
24777b8d048SJagan Teki 			  const void *txp, void *rxp, unsigned long flags)
24877b8d048SJagan Teki {
24977b8d048SJagan Teki 	ulong start;
25077b8d048SJagan Teki 	int chconf, i = 0;
25177b8d048SJagan Teki 
25277b8d048SJagan Teki 	chconf = readl(&priv->regs->channel[priv->cs].chconf);
25377b8d048SJagan Teki 
25477b8d048SJagan Teki 	/*Enable SPI channel*/
25577b8d048SJagan Teki 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
25677b8d048SJagan Teki 
25777b8d048SJagan Teki 	/*set TRANSMIT-RECEIVE Mode*/
25877b8d048SJagan Teki 	chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
25977b8d048SJagan Teki 	chconf |= (priv->wordlen - 1) << 7;
26077b8d048SJagan Teki 	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
26177b8d048SJagan Teki 	omap3_spi_write_chconf(priv, chconf);
26277b8d048SJagan Teki 
26377b8d048SJagan Teki 	/*Shift in and out 1 byte at time*/
26477b8d048SJagan Teki 	for (i=0; i < len; i++){
26577b8d048SJagan Teki 		/* Write: wait for TX empty (TXS == 1)*/
26677b8d048SJagan Teki 		start = get_timer(0);
26777b8d048SJagan Teki 		while (!(readl(&priv->regs->channel[priv->cs].chstat) &
26877b8d048SJagan Teki 			 OMAP3_MCSPI_CHSTAT_TXS)) {
26977b8d048SJagan Teki 			if (get_timer(start) > SPI_WAIT_TIMEOUT) {
27077b8d048SJagan Teki 				printf("SPI TXS timed out, status=0x%08x\n",
27177b8d048SJagan Teki 					readl(&priv->regs->channel[priv->cs].chstat));
27277b8d048SJagan Teki 				return -1;
27377b8d048SJagan Teki 			}
27477b8d048SJagan Teki 		}
27577b8d048SJagan Teki 		/* Write the data */
27677b8d048SJagan Teki 		unsigned int *tx = &priv->regs->channel[priv->cs].tx;
27777b8d048SJagan Teki 		if (priv->wordlen > 16)
27877b8d048SJagan Teki 			writel(((u32 *)txp)[i], tx);
27977b8d048SJagan Teki 		else if (priv->wordlen > 8)
28077b8d048SJagan Teki 			writel(((u16 *)txp)[i], tx);
28177b8d048SJagan Teki 		else
28277b8d048SJagan Teki 			writel(((u8 *)txp)[i], tx);
28377b8d048SJagan Teki 
28477b8d048SJagan Teki 		/*Read: wait for RX containing data (RXS == 1)*/
28577b8d048SJagan Teki 		start = get_timer(0);
28677b8d048SJagan Teki 		while (!(readl(&priv->regs->channel[priv->cs].chstat) &
28777b8d048SJagan Teki 			 OMAP3_MCSPI_CHSTAT_RXS)) {
28877b8d048SJagan Teki 			if (get_timer(start) > SPI_WAIT_TIMEOUT) {
28977b8d048SJagan Teki 				printf("SPI RXS timed out, status=0x%08x\n",
29077b8d048SJagan Teki 					readl(&priv->regs->channel[priv->cs].chstat));
29177b8d048SJagan Teki 				return -1;
29277b8d048SJagan Teki 			}
29377b8d048SJagan Teki 		}
29477b8d048SJagan Teki 		/* Read the data */
29577b8d048SJagan Teki 		unsigned int *rx = &priv->regs->channel[priv->cs].rx;
29677b8d048SJagan Teki 		if (priv->wordlen > 16)
29777b8d048SJagan Teki 			((u32 *)rxp)[i] = readl(rx);
29877b8d048SJagan Teki 		else if (priv->wordlen > 8)
29977b8d048SJagan Teki 			((u16 *)rxp)[i] = (u16)readl(rx);
30077b8d048SJagan Teki 		else
30177b8d048SJagan Teki 			((u8 *)rxp)[i] = (u8)readl(rx);
30277b8d048SJagan Teki 	}
30377b8d048SJagan Teki 	/* Disable the channel */
30477b8d048SJagan Teki 	omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
30577b8d048SJagan Teki 
30677b8d048SJagan Teki 	/*if transfer must be terminated disable the channel*/
30777b8d048SJagan Teki 	if (flags & SPI_XFER_END) {
30877b8d048SJagan Teki 		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
30977b8d048SJagan Teki 		omap3_spi_write_chconf(priv, chconf);
31077b8d048SJagan Teki 	}
31177b8d048SJagan Teki 
31277b8d048SJagan Teki 	return 0;
31377b8d048SJagan Teki }
31477b8d048SJagan Teki 
_spi_xfer(struct omap3_spi_priv * priv,unsigned int bitlen,const void * dout,void * din,unsigned long flags)31577b8d048SJagan Teki static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen,
31677b8d048SJagan Teki 		     const void *dout, void *din, unsigned long flags)
31777b8d048SJagan Teki {
31877b8d048SJagan Teki 	unsigned int	len;
31977b8d048SJagan Teki 	int ret = -1;
32077b8d048SJagan Teki 
32177b8d048SJagan Teki 	if (priv->wordlen < 4 || priv->wordlen > 32) {
32277b8d048SJagan Teki 		printf("omap3_spi: invalid wordlen %d\n", priv->wordlen);
32377b8d048SJagan Teki 		return -1;
32477b8d048SJagan Teki 	}
32577b8d048SJagan Teki 
32677b8d048SJagan Teki 	if (bitlen % priv->wordlen)
32777b8d048SJagan Teki 		return -1;
32877b8d048SJagan Teki 
32977b8d048SJagan Teki 	len = bitlen / priv->wordlen;
33077b8d048SJagan Teki 
33177b8d048SJagan Teki 	if (bitlen == 0) {	 /* only change CS */
33277b8d048SJagan Teki 		int chconf = readl(&priv->regs->channel[priv->cs].chconf);
33377b8d048SJagan Teki 
33477b8d048SJagan Teki 		if (flags & SPI_XFER_BEGIN) {
33577b8d048SJagan Teki 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
33677b8d048SJagan Teki 			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
33777b8d048SJagan Teki 			omap3_spi_write_chconf(priv, chconf);
33877b8d048SJagan Teki 		}
33977b8d048SJagan Teki 		if (flags & SPI_XFER_END) {
34077b8d048SJagan Teki 			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
34177b8d048SJagan Teki 			omap3_spi_write_chconf(priv, chconf);
34277b8d048SJagan Teki 			omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
34377b8d048SJagan Teki 		}
34477b8d048SJagan Teki 		ret = 0;
34577b8d048SJagan Teki 	} else {
34677b8d048SJagan Teki 		if (dout != NULL && din != NULL)
34777b8d048SJagan Teki 			ret = omap3_spi_txrx(priv, len, dout, din, flags);
34877b8d048SJagan Teki 		else if (dout != NULL)
34977b8d048SJagan Teki 			ret = omap3_spi_write(priv, len, dout, flags);
35077b8d048SJagan Teki 		else if (din != NULL)
35177b8d048SJagan Teki 			ret = omap3_spi_read(priv, len, din, flags);
35277b8d048SJagan Teki 	}
35377b8d048SJagan Teki 	return ret;
35477b8d048SJagan Teki }
35577b8d048SJagan Teki 
_omap3_spi_set_speed(struct omap3_spi_priv * priv)35677b8d048SJagan Teki static void _omap3_spi_set_speed(struct omap3_spi_priv *priv)
35777b8d048SJagan Teki {
35877b8d048SJagan Teki 	uint32_t confr, div = 0;
35977b8d048SJagan Teki 
36077b8d048SJagan Teki 	confr = readl(&priv->regs->channel[priv->cs].chconf);
36177b8d048SJagan Teki 
36277b8d048SJagan Teki 	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
36377b8d048SJagan Teki 	if (priv->freq) {
36477b8d048SJagan Teki 		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
36577b8d048SJagan Teki 					> priv->freq)
36677b8d048SJagan Teki 			div++;
36777b8d048SJagan Teki 	} else {
36877b8d048SJagan Teki 		 div = 0xC;
36977b8d048SJagan Teki 	}
37077b8d048SJagan Teki 
37177b8d048SJagan Teki 	/* set clock divisor */
37277b8d048SJagan Teki 	confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
37377b8d048SJagan Teki 	confr |= div << 2;
37477b8d048SJagan Teki 
37577b8d048SJagan Teki 	omap3_spi_write_chconf(priv, confr);
37677b8d048SJagan Teki }
37777b8d048SJagan Teki 
_omap3_spi_set_mode(struct omap3_spi_priv * priv)37877b8d048SJagan Teki static void _omap3_spi_set_mode(struct omap3_spi_priv *priv)
37977b8d048SJagan Teki {
38077b8d048SJagan Teki 	uint32_t confr;
38177b8d048SJagan Teki 
38277b8d048SJagan Teki 	confr = readl(&priv->regs->channel[priv->cs].chconf);
38377b8d048SJagan Teki 
38477b8d048SJagan Teki 	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
38577b8d048SJagan Teki 	 * REVISIT: this controller could support SPI_3WIRE mode.
38677b8d048SJagan Teki 	 */
38777b8d048SJagan Teki 	if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
38877b8d048SJagan Teki 		confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
38977b8d048SJagan Teki 		confr |= OMAP3_MCSPI_CHCONF_DPE0;
39077b8d048SJagan Teki 	} else {
39177b8d048SJagan Teki 		confr &= ~OMAP3_MCSPI_CHCONF_DPE0;
39277b8d048SJagan Teki 		confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
39377b8d048SJagan Teki 	}
39477b8d048SJagan Teki 
39577b8d048SJagan Teki 	/* set SPI mode 0..3 */
39677b8d048SJagan Teki 	confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA);
39777b8d048SJagan Teki 	if (priv->mode & SPI_CPHA)
39877b8d048SJagan Teki 		confr |= OMAP3_MCSPI_CHCONF_PHA;
39977b8d048SJagan Teki 	if (priv->mode & SPI_CPOL)
40077b8d048SJagan Teki 		confr |= OMAP3_MCSPI_CHCONF_POL;
40177b8d048SJagan Teki 
40277b8d048SJagan Teki 	/* set chipselect polarity; manage with FORCE */
40377b8d048SJagan Teki 	if (!(priv->mode & SPI_CS_HIGH))
40477b8d048SJagan Teki 		confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
40577b8d048SJagan Teki 	else
40677b8d048SJagan Teki 		confr &= ~OMAP3_MCSPI_CHCONF_EPOL;
40777b8d048SJagan Teki 
40877b8d048SJagan Teki 	/* Transmit & receive mode */
40977b8d048SJagan Teki 	confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
41077b8d048SJagan Teki 
41177b8d048SJagan Teki 	omap3_spi_write_chconf(priv, confr);
41277b8d048SJagan Teki }
41377b8d048SJagan Teki 
_omap3_spi_set_wordlen(struct omap3_spi_priv * priv)41477b8d048SJagan Teki static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv)
41577b8d048SJagan Teki {
41677b8d048SJagan Teki 	unsigned int confr;
41777b8d048SJagan Teki 
41877b8d048SJagan Teki 	/* McSPI individual channel configuration */
41977b8d048SJagan Teki 	confr = readl(&priv->regs->channel[priv->wordlen].chconf);
42077b8d048SJagan Teki 
42177b8d048SJagan Teki 	/* wordlength */
42277b8d048SJagan Teki 	confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
42377b8d048SJagan Teki 	confr |= (priv->wordlen - 1) << 7;
42477b8d048SJagan Teki 
42577b8d048SJagan Teki 	omap3_spi_write_chconf(priv, confr);
42677b8d048SJagan Teki }
42777b8d048SJagan Teki 
spi_reset(struct mcspi * regs)42877b8d048SJagan Teki static void spi_reset(struct mcspi *regs)
42977b8d048SJagan Teki {
43077b8d048SJagan Teki 	unsigned int tmp;
43177b8d048SJagan Teki 
43277b8d048SJagan Teki 	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &regs->sysconfig);
43377b8d048SJagan Teki 	do {
43477b8d048SJagan Teki 		tmp = readl(&regs->sysstatus);
43577b8d048SJagan Teki 	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
43677b8d048SJagan Teki 
43777b8d048SJagan Teki 	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
43877b8d048SJagan Teki 	       OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
43977b8d048SJagan Teki 	       OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, &regs->sysconfig);
44077b8d048SJagan Teki 
44177b8d048SJagan Teki 	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &regs->wakeupenable);
44277b8d048SJagan Teki }
44377b8d048SJagan Teki 
_omap3_spi_claim_bus(struct omap3_spi_priv * priv)44477b8d048SJagan Teki static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv)
44577b8d048SJagan Teki {
44677b8d048SJagan Teki 	unsigned int conf;
44777b8d048SJagan Teki 
44877b8d048SJagan Teki 	spi_reset(priv->regs);
44977b8d048SJagan Teki 
45077b8d048SJagan Teki 	/*
45177b8d048SJagan Teki 	 * setup when switching from (reset default) slave mode
45277b8d048SJagan Teki 	 * to single-channel master mode
45377b8d048SJagan Teki 	 */
45477b8d048SJagan Teki 	conf = readl(&priv->regs->modulctrl);
45577b8d048SJagan Teki 	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
45677b8d048SJagan Teki 	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
45777b8d048SJagan Teki 
45877b8d048SJagan Teki 	writel(conf, &priv->regs->modulctrl);
45977b8d048SJagan Teki }
46077b8d048SJagan Teki 
46177b8d048SJagan Teki #ifndef CONFIG_DM_SPI
46277b8d048SJagan Teki 
to_omap3_spi(struct spi_slave * slave)46341bccb81SJagan Teki static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave)
464682c1723SJagan Teki {
46541bccb81SJagan Teki 	return container_of(slave, struct omap3_spi_priv, slave);
466682c1723SJagan Teki }
467682c1723SJagan Teki 
spi_init(void)46877b8d048SJagan Teki void spi_init(void)
46953736baaSDirk Behme {
47053736baaSDirk Behme 	/* do nothing */
47153736baaSDirk Behme }
47253736baaSDirk Behme 
spi_free_slave(struct spi_slave * slave)47377b8d048SJagan Teki void spi_free_slave(struct spi_slave *slave)
47477b8d048SJagan Teki {
47541bccb81SJagan Teki 	struct omap3_spi_priv *priv = to_omap3_spi(slave);
47677b8d048SJagan Teki 
47741bccb81SJagan Teki 	free(priv);
47877b8d048SJagan Teki }
47977b8d048SJagan Teki 
spi_claim_bus(struct spi_slave * slave)48077b8d048SJagan Teki int spi_claim_bus(struct spi_slave *slave)
48177b8d048SJagan Teki {
48241bccb81SJagan Teki 	struct omap3_spi_priv *priv = to_omap3_spi(slave);
48341bccb81SJagan Teki 
48477b8d048SJagan Teki 	_omap3_spi_claim_bus(priv);
48577b8d048SJagan Teki 	_omap3_spi_set_wordlen(priv);
48677b8d048SJagan Teki 	_omap3_spi_set_mode(priv);
48777b8d048SJagan Teki 	_omap3_spi_set_speed(priv);
48877b8d048SJagan Teki 
48977b8d048SJagan Teki 	return 0;
49077b8d048SJagan Teki }
49177b8d048SJagan Teki 
spi_release_bus(struct spi_slave * slave)49277b8d048SJagan Teki void spi_release_bus(struct spi_slave *slave)
49377b8d048SJagan Teki {
49441bccb81SJagan Teki 	struct omap3_spi_priv *priv = to_omap3_spi(slave);
49541bccb81SJagan Teki 
49677b8d048SJagan Teki 	/* Reset the SPI hardware */
49777b8d048SJagan Teki 	spi_reset(priv->regs);
49877b8d048SJagan Teki }
49977b8d048SJagan Teki 
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)50053736baaSDirk Behme struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
50153736baaSDirk Behme 				     unsigned int max_hz, unsigned int mode)
50253736baaSDirk Behme {
50341bccb81SJagan Teki 	struct omap3_spi_priv *priv;
504d3504feeSSimon Glass 	struct mcspi *regs;
50553736baaSDirk Behme 
50653736baaSDirk Behme 	/*
50753736baaSDirk Behme 	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
50853736baaSDirk Behme 	 * with different number of chip selects (CS, channels):
50953736baaSDirk Behme 	 * McSPI1 has 4 CS (bus 0, cs 0 - 3)
51053736baaSDirk Behme 	 * McSPI2 has 2 CS (bus 1, cs 0 - 1)
51153736baaSDirk Behme 	 * McSPI3 has 2 CS (bus 2, cs 0 - 1)
51253736baaSDirk Behme 	 * McSPI4 has 1 CS (bus 3, cs 0)
51353736baaSDirk Behme 	 */
51453736baaSDirk Behme 
51553736baaSDirk Behme 	switch (bus) {
51653736baaSDirk Behme 	case 0:
517d3504feeSSimon Glass 		 regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
51853736baaSDirk Behme 		 break;
5194c0620bfSTom Rini #ifdef OMAP3_MCSPI2_BASE
52053736baaSDirk Behme 	case 1:
521d3504feeSSimon Glass 		 regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
52253736baaSDirk Behme 		 break;
5234c0620bfSTom Rini #endif
5244c0620bfSTom Rini #ifdef OMAP3_MCSPI3_BASE
52553736baaSDirk Behme 	case 2:
526d3504feeSSimon Glass 		 regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
52753736baaSDirk Behme 		 break;
5284c0620bfSTom Rini #endif
5294c0620bfSTom Rini #ifdef OMAP3_MCSPI4_BASE
53053736baaSDirk Behme 	case 3:
531d3504feeSSimon Glass 		 regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
53253736baaSDirk Behme 		 break;
5334c0620bfSTom Rini #endif
53453736baaSDirk Behme 	default:
53577b8d048SJagan Teki 		 printf("SPI error: unsupported bus %i.  Supported busses 0 - 3\n", bus);
53653736baaSDirk Behme 		 return NULL;
53753736baaSDirk Behme 	}
53853736baaSDirk Behme 
53953736baaSDirk Behme 	if (((bus == 0) && (cs > 3)) ||
54053736baaSDirk Behme 	    ((bus == 1) && (cs > 1)) ||
54153736baaSDirk Behme 	    ((bus == 2) && (cs > 1)) ||
54253736baaSDirk Behme 	    ((bus == 3) && (cs > 0))) {
54377b8d048SJagan Teki 		printf("SPI error: unsupported chip select %i on bus %i\n", cs, bus);
54453736baaSDirk Behme 		return NULL;
54553736baaSDirk Behme 	}
54653736baaSDirk Behme 
54753736baaSDirk Behme 	if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
54853854334SHeinrich Schuchardt 		printf("SPI error: unsupported frequency %i Hz. Max frequency is 48 MHz\n",
54953854334SHeinrich Schuchardt 		       max_hz);
55053736baaSDirk Behme 		return NULL;
55153736baaSDirk Behme 	}
55253736baaSDirk Behme 
55353736baaSDirk Behme 	if (mode > SPI_MODE_3) {
55453736baaSDirk Behme 		printf("SPI error: unsupported SPI mode %i\n", mode);
55553736baaSDirk Behme 		return NULL;
55653736baaSDirk Behme 	}
557d3504feeSSimon Glass 
55841bccb81SJagan Teki 	priv = spi_alloc_slave(struct omap3_spi_priv, bus, cs);
55941bccb81SJagan Teki 	if (!priv) {
560d3504feeSSimon Glass 		printf("SPI error: malloc of SPI structure failed\n");
561d3504feeSSimon Glass 		return NULL;
562d3504feeSSimon Glass 	}
563d3504feeSSimon Glass 
56477b8d048SJagan Teki 	priv->regs = regs;
56577b8d048SJagan Teki 	priv->cs = cs;
56677b8d048SJagan Teki 	priv->freq = max_hz;
56777b8d048SJagan Teki 	priv->mode = mode;
56841bccb81SJagan Teki 	priv->wordlen = priv->slave.wordlen;
56925eaa288STom Rini #if 0
57025eaa288STom Rini 	/* Please migrate to DM_SPI support for this feature. */
57177b8d048SJagan Teki 	priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
57277b8d048SJagan Teki #endif
57353736baaSDirk Behme 
57441bccb81SJagan Teki 	return &priv->slave;
57553736baaSDirk Behme }
57653736baaSDirk Behme 
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)57753736baaSDirk Behme int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
57853736baaSDirk Behme 	     const void *dout, void *din, unsigned long flags)
57941bccb81SJagan Teki {
58041bccb81SJagan Teki 	struct omap3_spi_priv *priv = to_omap3_spi(slave);
58141bccb81SJagan Teki 
58241bccb81SJagan Teki 	return _spi_xfer(priv, bitlen, dout, din, flags);
58341bccb81SJagan Teki }
58477b8d048SJagan Teki 
58577b8d048SJagan Teki #else
58677b8d048SJagan Teki 
omap3_spi_claim_bus(struct udevice * dev)58777b8d048SJagan Teki static int omap3_spi_claim_bus(struct udevice *dev)
58853736baaSDirk Behme {
58977b8d048SJagan Teki 	struct udevice *bus = dev->parent;
59077b8d048SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
59177b8d048SJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
59253736baaSDirk Behme 
59377b8d048SJagan Teki 	priv->cs = slave_plat->cs;
59477b8d048SJagan Teki 	_omap3_spi_claim_bus(priv);
59577b8d048SJagan Teki 
59677b8d048SJagan Teki 	return 0;
5975753d09bSNikita Kiryanov }
5985753d09bSNikita Kiryanov 
omap3_spi_release_bus(struct udevice * dev)59977b8d048SJagan Teki static int omap3_spi_release_bus(struct udevice *dev)
60053736baaSDirk Behme {
60177b8d048SJagan Teki 	struct udevice *bus = dev->parent;
60277b8d048SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
60377b8d048SJagan Teki 
60477b8d048SJagan Teki 	/* Reset the SPI hardware */
60577b8d048SJagan Teki 	spi_reset(priv->regs);
60677b8d048SJagan Teki 
60777b8d048SJagan Teki 	return 0;
60853736baaSDirk Behme }
60953736baaSDirk Behme 
omap3_spi_set_wordlen(struct udevice * dev,unsigned int wordlen)61077b8d048SJagan Teki static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
61153736baaSDirk Behme {
61277b8d048SJagan Teki 	struct udevice *bus = dev->parent;
61377b8d048SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
61477b8d048SJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
61577b8d048SJagan Teki 
61677b8d048SJagan Teki 	priv->cs = slave_plat->cs;
61777b8d048SJagan Teki 	priv->wordlen = wordlen;
61877b8d048SJagan Teki 	_omap3_spi_set_wordlen(priv);
61977b8d048SJagan Teki 
62077b8d048SJagan Teki 	return 0;
62153736baaSDirk Behme }
62253736baaSDirk Behme 
omap3_spi_probe(struct udevice * dev)62377b8d048SJagan Teki static int omap3_spi_probe(struct udevice *dev)
62453736baaSDirk Behme {
62577b8d048SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(dev);
62677b8d048SJagan Teki 	const void *blob = gd->fdt_blob;
627e160f7d4SSimon Glass 	int node = dev_of_offset(dev);
62877b8d048SJagan Teki 
6295f89a15eSMartin Hejnfelt 	struct omap2_mcspi_platform_config* data =
6305f89a15eSMartin Hejnfelt 		(struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
6315f89a15eSMartin Hejnfelt 
632a821c4afSSimon Glass 	priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset);
633*cafc6911SSjoerd Simons 	if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
634*cafc6911SSjoerd Simons 		priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
635*cafc6911SSjoerd Simons 	else
636*cafc6911SSjoerd Simons 		priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
63777b8d048SJagan Teki 	priv->wordlen = SPI_DEFAULT_WORDLEN;
63877b8d048SJagan Teki 	return 0;
63953736baaSDirk Behme }
64077b8d048SJagan Teki 
omap3_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)64177b8d048SJagan Teki static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen,
64277b8d048SJagan Teki 			    const void *dout, void *din, unsigned long flags)
64377b8d048SJagan Teki {
64477b8d048SJagan Teki 	struct udevice *bus = dev->parent;
64577b8d048SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
64677b8d048SJagan Teki 
64777b8d048SJagan Teki 	return _spi_xfer(priv, bitlen, dout, din, flags);
64877b8d048SJagan Teki }
64977b8d048SJagan Teki 
omap3_spi_set_speed(struct udevice * dev,unsigned int speed)65043e86b9aSJagan Teki static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed)
65177b8d048SJagan Teki {
652226998e3SJagan Teki 	struct udevice *bus = dev->parent;
653226998e3SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
654226998e3SJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
655226998e3SJagan Teki 
656226998e3SJagan Teki 	priv->cs = slave_plat->cs;
657226998e3SJagan Teki 	priv->freq = slave_plat->max_hz;
658226998e3SJagan Teki 	_omap3_spi_set_speed(priv);
659226998e3SJagan Teki 
66077b8d048SJagan Teki 	return 0;
66177b8d048SJagan Teki }
66277b8d048SJagan Teki 
omap3_spi_set_mode(struct udevice * dev,uint mode)66343e86b9aSJagan Teki static int omap3_spi_set_mode(struct udevice *dev, uint mode)
66477b8d048SJagan Teki {
665226998e3SJagan Teki 	struct udevice *bus = dev->parent;
666226998e3SJagan Teki 	struct omap3_spi_priv *priv = dev_get_priv(bus);
667226998e3SJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
668226998e3SJagan Teki 
669226998e3SJagan Teki 	priv->cs = slave_plat->cs;
670226998e3SJagan Teki 	priv->mode = slave_plat->mode;
671226998e3SJagan Teki 	_omap3_spi_set_mode(priv);
672226998e3SJagan Teki 
67377b8d048SJagan Teki 	return 0;
67477b8d048SJagan Teki }
67577b8d048SJagan Teki 
67677b8d048SJagan Teki static const struct dm_spi_ops omap3_spi_ops = {
67777b8d048SJagan Teki 	.claim_bus      = omap3_spi_claim_bus,
67877b8d048SJagan Teki 	.release_bus    = omap3_spi_release_bus,
67977b8d048SJagan Teki 	.set_wordlen    = omap3_spi_set_wordlen,
68077b8d048SJagan Teki 	.xfer	    = omap3_spi_xfer,
68177b8d048SJagan Teki 	.set_speed      = omap3_spi_set_speed,
68277b8d048SJagan Teki 	.set_mode	= omap3_spi_set_mode,
68377b8d048SJagan Teki 	/*
68477b8d048SJagan Teki 	 * cs_info is not needed, since we require all chip selects to be
68577b8d048SJagan Teki 	 * in the device tree explicitly
68677b8d048SJagan Teki 	 */
68777b8d048SJagan Teki };
68877b8d048SJagan Teki 
6895f89a15eSMartin Hejnfelt static struct omap2_mcspi_platform_config omap2_pdata = {
6905f89a15eSMartin Hejnfelt 	.regs_offset = 0,
6915f89a15eSMartin Hejnfelt };
6925f89a15eSMartin Hejnfelt 
6935f89a15eSMartin Hejnfelt static struct omap2_mcspi_platform_config omap4_pdata = {
6945f89a15eSMartin Hejnfelt 	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
6955f89a15eSMartin Hejnfelt };
6965f89a15eSMartin Hejnfelt 
69777b8d048SJagan Teki static const struct udevice_id omap3_spi_ids[] = {
6985f89a15eSMartin Hejnfelt 	{ .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata },
6995f89a15eSMartin Hejnfelt 	{ .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata },
70077b8d048SJagan Teki 	{ }
70177b8d048SJagan Teki };
70277b8d048SJagan Teki 
70377b8d048SJagan Teki U_BOOT_DRIVER(omap3_spi) = {
70477b8d048SJagan Teki 	.name   = "omap3_spi",
70577b8d048SJagan Teki 	.id     = UCLASS_SPI,
70677b8d048SJagan Teki 	.of_match = omap3_spi_ids,
70777b8d048SJagan Teki 	.probe = omap3_spi_probe,
70877b8d048SJagan Teki 	.ops    = &omap3_spi_ops,
70977b8d048SJagan Teki 	.priv_auto_alloc_size = sizeof(struct omap3_spi_priv),
71077b8d048SJagan Teki };
71177b8d048SJagan Teki #endif
712