183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
253736baaSDirk Behme /*
377b8d048SJagan Teki * Copyright (C) 2016 Jagan Teki <jteki@openedev.com>
477b8d048SJagan Teki * Christophe Ricard <christophe.ricard@gmail.com>
577b8d048SJagan Teki *
653736baaSDirk Behme * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
753736baaSDirk Behme *
853736baaSDirk Behme * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
953736baaSDirk Behme * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
1053736baaSDirk Behme *
1153736baaSDirk Behme * Copyright (C) 2007 Atmel Corporation
1253736baaSDirk Behme *
1353736baaSDirk Behme * Parts taken from linux/drivers/spi/omap2_mcspi.c
1453736baaSDirk Behme * Copyright (C) 2005, 2006 Nokia Corporation
1553736baaSDirk Behme *
1653736baaSDirk Behme * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com>
1753736baaSDirk Behme */
1853736baaSDirk Behme
1953736baaSDirk Behme #include <common.h>
2077b8d048SJagan Teki #include <dm.h>
2153736baaSDirk Behme #include <spi.h>
2253736baaSDirk Behme #include <malloc.h>
2353736baaSDirk Behme #include <asm/io.h>
2453736baaSDirk Behme
2577b8d048SJagan Teki DECLARE_GLOBAL_DATA_PTR;
2677b8d048SJagan Teki
27682c1723SJagan Teki #if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
28682c1723SJagan Teki #define OMAP3_MCSPI1_BASE 0x48030100
29682c1723SJagan Teki #define OMAP3_MCSPI2_BASE 0x481A0100
30682c1723SJagan Teki #else
31682c1723SJagan Teki #define OMAP3_MCSPI1_BASE 0x48098000
32682c1723SJagan Teki #define OMAP3_MCSPI2_BASE 0x4809A000
33682c1723SJagan Teki #define OMAP3_MCSPI3_BASE 0x480B8000
34682c1723SJagan Teki #define OMAP3_MCSPI4_BASE 0x480BA000
35682c1723SJagan Teki #endif
36682c1723SJagan Teki
375f89a15eSMartin Hejnfelt #define OMAP4_MCSPI_REG_OFFSET 0x100
385f89a15eSMartin Hejnfelt
395f89a15eSMartin Hejnfelt struct omap2_mcspi_platform_config {
405f89a15eSMartin Hejnfelt unsigned int regs_offset;
415f89a15eSMartin Hejnfelt };
425f89a15eSMartin Hejnfelt
43682c1723SJagan Teki /* per-register bitmasks */
44682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
45682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
46682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0)
47682c1723SJagan Teki #define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1)
48682c1723SJagan Teki
49682c1723SJagan Teki #define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0)
50682c1723SJagan Teki
51682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0)
52682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_MS BIT(2)
53682c1723SJagan Teki #define OMAP3_MCSPI_MODULCTRL_STEST BIT(3)
54682c1723SJagan Teki
55682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_PHA BIT(0)
56682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_POL BIT(1)
57682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2)
58682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_EPOL BIT(6)
59682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7)
60682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12)
61682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13)
62682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12)
63682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DMAW BIT(14)
64682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DMAR BIT(15)
65682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DPE0 BIT(16)
66682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_DPE1 BIT(17)
67682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_IS BIT(18)
68682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_TURBO BIT(19)
69682c1723SJagan Teki #define OMAP3_MCSPI_CHCONF_FORCE BIT(20)
70682c1723SJagan Teki
71682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_RXS BIT(0)
72682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_TXS BIT(1)
73682c1723SJagan Teki #define OMAP3_MCSPI_CHSTAT_EOT BIT(2)
74682c1723SJagan Teki
75682c1723SJagan Teki #define OMAP3_MCSPI_CHCTRL_EN BIT(0)
76682c1723SJagan Teki #define OMAP3_MCSPI_CHCTRL_DIS (0 << 0)
77682c1723SJagan Teki
78682c1723SJagan Teki #define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0)
7977b8d048SJagan Teki #define MCSPI_PINDIR_D0_IN_D1_OUT 0
8077b8d048SJagan Teki #define MCSPI_PINDIR_D0_OUT_D1_IN 1
81682c1723SJagan Teki
82682c1723SJagan Teki #define OMAP3_MCSPI_MAX_FREQ 48000000
83611c9ba2SDavid Dueck #define SPI_WAIT_TIMEOUT 10
8453736baaSDirk Behme
85682c1723SJagan Teki /* OMAP3 McSPI registers */
86682c1723SJagan Teki struct mcspi_channel {
87682c1723SJagan Teki unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */
88682c1723SJagan Teki unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */
89682c1723SJagan Teki unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */
90682c1723SJagan Teki unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */
91682c1723SJagan Teki unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */
92682c1723SJagan Teki };
93682c1723SJagan Teki
94682c1723SJagan Teki struct mcspi {
95682c1723SJagan Teki unsigned char res1[0x10];
96682c1723SJagan Teki unsigned int sysconfig; /* 0x10 */
97682c1723SJagan Teki unsigned int sysstatus; /* 0x14 */
98682c1723SJagan Teki unsigned int irqstatus; /* 0x18 */
99682c1723SJagan Teki unsigned int irqenable; /* 0x1C */
100682c1723SJagan Teki unsigned int wakeupenable; /* 0x20 */
101682c1723SJagan Teki unsigned int syst; /* 0x24 */
102682c1723SJagan Teki unsigned int modulctrl; /* 0x28 */
103682c1723SJagan Teki struct mcspi_channel channel[4];
104682c1723SJagan Teki /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */
105682c1723SJagan Teki /* channel1: 0x40 - 0x50, bus 0 & 1 */
106682c1723SJagan Teki /* channel2: 0x54 - 0x64, bus 0 & 1 */
107682c1723SJagan Teki /* channel3: 0x68 - 0x78, bus 0 */
108682c1723SJagan Teki };
109682c1723SJagan Teki
11077b8d048SJagan Teki struct omap3_spi_priv {
11141bccb81SJagan Teki #ifndef CONFIG_DM_SPI
11241bccb81SJagan Teki struct spi_slave slave;
11341bccb81SJagan Teki #endif
114682c1723SJagan Teki struct mcspi *regs;
11577b8d048SJagan Teki unsigned int cs;
116682c1723SJagan Teki unsigned int freq;
117682c1723SJagan Teki unsigned int mode;
11877b8d048SJagan Teki unsigned int wordlen;
11977b8d048SJagan Teki unsigned int pin_dir:1;
120682c1723SJagan Teki };
121682c1723SJagan Teki
omap3_spi_write_chconf(struct omap3_spi_priv * priv,int val)12277b8d048SJagan Teki static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val)
12377b8d048SJagan Teki {
12477b8d048SJagan Teki writel(val, &priv->regs->channel[priv->cs].chconf);
12577b8d048SJagan Teki /* Flash post writes to make immediate effect */
12677b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chconf);
12777b8d048SJagan Teki }
12877b8d048SJagan Teki
omap3_spi_set_enable(struct omap3_spi_priv * priv,int enable)12977b8d048SJagan Teki static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable)
13077b8d048SJagan Teki {
13177b8d048SJagan Teki writel(enable, &priv->regs->channel[priv->cs].chctrl);
13277b8d048SJagan Teki /* Flash post writes to make immediate effect */
13377b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chctrl);
13477b8d048SJagan Teki }
13577b8d048SJagan Teki
omap3_spi_write(struct omap3_spi_priv * priv,unsigned int len,const void * txp,unsigned long flags)13677b8d048SJagan Teki static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len,
13777b8d048SJagan Teki const void *txp, unsigned long flags)
13877b8d048SJagan Teki {
13977b8d048SJagan Teki ulong start;
14077b8d048SJagan Teki int i, chconf;
14177b8d048SJagan Teki
14277b8d048SJagan Teki chconf = readl(&priv->regs->channel[priv->cs].chconf);
14377b8d048SJagan Teki
14477b8d048SJagan Teki /* Enable the channel */
14577b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
14677b8d048SJagan Teki
14777b8d048SJagan Teki chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
14877b8d048SJagan Teki chconf |= (priv->wordlen - 1) << 7;
14977b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
15077b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_FORCE;
15177b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
15277b8d048SJagan Teki
15377b8d048SJagan Teki for (i = 0; i < len; i++) {
15477b8d048SJagan Teki /* wait till TX register is empty (TXS == 1) */
15577b8d048SJagan Teki start = get_timer(0);
15677b8d048SJagan Teki while (!(readl(&priv->regs->channel[priv->cs].chstat) &
15777b8d048SJagan Teki OMAP3_MCSPI_CHSTAT_TXS)) {
15877b8d048SJagan Teki if (get_timer(start) > SPI_WAIT_TIMEOUT) {
15977b8d048SJagan Teki printf("SPI TXS timed out, status=0x%08x\n",
16077b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chstat));
16177b8d048SJagan Teki return -1;
16277b8d048SJagan Teki }
16377b8d048SJagan Teki }
16477b8d048SJagan Teki /* Write the data */
16577b8d048SJagan Teki unsigned int *tx = &priv->regs->channel[priv->cs].tx;
16677b8d048SJagan Teki if (priv->wordlen > 16)
16777b8d048SJagan Teki writel(((u32 *)txp)[i], tx);
16877b8d048SJagan Teki else if (priv->wordlen > 8)
16977b8d048SJagan Teki writel(((u16 *)txp)[i], tx);
17077b8d048SJagan Teki else
17177b8d048SJagan Teki writel(((u8 *)txp)[i], tx);
17277b8d048SJagan Teki }
17377b8d048SJagan Teki
17477b8d048SJagan Teki /* wait to finish of transfer */
17577b8d048SJagan Teki while ((readl(&priv->regs->channel[priv->cs].chstat) &
17677b8d048SJagan Teki (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) !=
17777b8d048SJagan Teki (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS))
17877b8d048SJagan Teki ;
17977b8d048SJagan Teki
18077b8d048SJagan Teki /* Disable the channel otherwise the next immediate RX will get affected */
18177b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
18277b8d048SJagan Teki
18377b8d048SJagan Teki if (flags & SPI_XFER_END) {
18477b8d048SJagan Teki
18577b8d048SJagan Teki chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
18677b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
18777b8d048SJagan Teki }
18877b8d048SJagan Teki return 0;
18977b8d048SJagan Teki }
19077b8d048SJagan Teki
omap3_spi_read(struct omap3_spi_priv * priv,unsigned int len,void * rxp,unsigned long flags)19177b8d048SJagan Teki static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len,
19277b8d048SJagan Teki void *rxp, unsigned long flags)
19377b8d048SJagan Teki {
19477b8d048SJagan Teki int i, chconf;
19577b8d048SJagan Teki ulong start;
19677b8d048SJagan Teki
19777b8d048SJagan Teki chconf = readl(&priv->regs->channel[priv->cs].chconf);
19877b8d048SJagan Teki
19977b8d048SJagan Teki /* Enable the channel */
20077b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
20177b8d048SJagan Teki
20277b8d048SJagan Teki chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
20377b8d048SJagan Teki chconf |= (priv->wordlen - 1) << 7;
20477b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
20577b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_FORCE;
20677b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
20777b8d048SJagan Teki
20877b8d048SJagan Teki writel(0, &priv->regs->channel[priv->cs].tx);
20977b8d048SJagan Teki
21077b8d048SJagan Teki for (i = 0; i < len; i++) {
21177b8d048SJagan Teki start = get_timer(0);
21277b8d048SJagan Teki /* Wait till RX register contains data (RXS == 1) */
21377b8d048SJagan Teki while (!(readl(&priv->regs->channel[priv->cs].chstat) &
21477b8d048SJagan Teki OMAP3_MCSPI_CHSTAT_RXS)) {
21577b8d048SJagan Teki if (get_timer(start) > SPI_WAIT_TIMEOUT) {
21677b8d048SJagan Teki printf("SPI RXS timed out, status=0x%08x\n",
21777b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chstat));
21877b8d048SJagan Teki return -1;
21977b8d048SJagan Teki }
22077b8d048SJagan Teki }
22177b8d048SJagan Teki
22277b8d048SJagan Teki /* Disable the channel to prevent furher receiving */
22377b8d048SJagan Teki if (i == (len - 1))
22477b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
22577b8d048SJagan Teki
22677b8d048SJagan Teki /* Read the data */
22777b8d048SJagan Teki unsigned int *rx = &priv->regs->channel[priv->cs].rx;
22877b8d048SJagan Teki if (priv->wordlen > 16)
22977b8d048SJagan Teki ((u32 *)rxp)[i] = readl(rx);
23077b8d048SJagan Teki else if (priv->wordlen > 8)
23177b8d048SJagan Teki ((u16 *)rxp)[i] = (u16)readl(rx);
23277b8d048SJagan Teki else
23377b8d048SJagan Teki ((u8 *)rxp)[i] = (u8)readl(rx);
23477b8d048SJagan Teki }
23577b8d048SJagan Teki
23677b8d048SJagan Teki if (flags & SPI_XFER_END) {
23777b8d048SJagan Teki chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
23877b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
23977b8d048SJagan Teki }
24077b8d048SJagan Teki
24177b8d048SJagan Teki return 0;
24277b8d048SJagan Teki }
24377b8d048SJagan Teki
24477b8d048SJagan Teki /*McSPI Transmit Receive Mode*/
omap3_spi_txrx(struct omap3_spi_priv * priv,unsigned int len,const void * txp,void * rxp,unsigned long flags)24577b8d048SJagan Teki static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len,
24677b8d048SJagan Teki const void *txp, void *rxp, unsigned long flags)
24777b8d048SJagan Teki {
24877b8d048SJagan Teki ulong start;
24977b8d048SJagan Teki int chconf, i = 0;
25077b8d048SJagan Teki
25177b8d048SJagan Teki chconf = readl(&priv->regs->channel[priv->cs].chconf);
25277b8d048SJagan Teki
25377b8d048SJagan Teki /*Enable SPI channel*/
25477b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
25577b8d048SJagan Teki
25677b8d048SJagan Teki /*set TRANSMIT-RECEIVE Mode*/
25777b8d048SJagan Teki chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK);
25877b8d048SJagan Teki chconf |= (priv->wordlen - 1) << 7;
25977b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_FORCE;
26077b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
26177b8d048SJagan Teki
26277b8d048SJagan Teki /*Shift in and out 1 byte at time*/
26377b8d048SJagan Teki for (i=0; i < len; i++){
26477b8d048SJagan Teki /* Write: wait for TX empty (TXS == 1)*/
26577b8d048SJagan Teki start = get_timer(0);
26677b8d048SJagan Teki while (!(readl(&priv->regs->channel[priv->cs].chstat) &
26777b8d048SJagan Teki OMAP3_MCSPI_CHSTAT_TXS)) {
26877b8d048SJagan Teki if (get_timer(start) > SPI_WAIT_TIMEOUT) {
26977b8d048SJagan Teki printf("SPI TXS timed out, status=0x%08x\n",
27077b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chstat));
27177b8d048SJagan Teki return -1;
27277b8d048SJagan Teki }
27377b8d048SJagan Teki }
27477b8d048SJagan Teki /* Write the data */
27577b8d048SJagan Teki unsigned int *tx = &priv->regs->channel[priv->cs].tx;
27677b8d048SJagan Teki if (priv->wordlen > 16)
27777b8d048SJagan Teki writel(((u32 *)txp)[i], tx);
27877b8d048SJagan Teki else if (priv->wordlen > 8)
27977b8d048SJagan Teki writel(((u16 *)txp)[i], tx);
28077b8d048SJagan Teki else
28177b8d048SJagan Teki writel(((u8 *)txp)[i], tx);
28277b8d048SJagan Teki
28377b8d048SJagan Teki /*Read: wait for RX containing data (RXS == 1)*/
28477b8d048SJagan Teki start = get_timer(0);
28577b8d048SJagan Teki while (!(readl(&priv->regs->channel[priv->cs].chstat) &
28677b8d048SJagan Teki OMAP3_MCSPI_CHSTAT_RXS)) {
28777b8d048SJagan Teki if (get_timer(start) > SPI_WAIT_TIMEOUT) {
28877b8d048SJagan Teki printf("SPI RXS timed out, status=0x%08x\n",
28977b8d048SJagan Teki readl(&priv->regs->channel[priv->cs].chstat));
29077b8d048SJagan Teki return -1;
29177b8d048SJagan Teki }
29277b8d048SJagan Teki }
29377b8d048SJagan Teki /* Read the data */
29477b8d048SJagan Teki unsigned int *rx = &priv->regs->channel[priv->cs].rx;
29577b8d048SJagan Teki if (priv->wordlen > 16)
29677b8d048SJagan Teki ((u32 *)rxp)[i] = readl(rx);
29777b8d048SJagan Teki else if (priv->wordlen > 8)
29877b8d048SJagan Teki ((u16 *)rxp)[i] = (u16)readl(rx);
29977b8d048SJagan Teki else
30077b8d048SJagan Teki ((u8 *)rxp)[i] = (u8)readl(rx);
30177b8d048SJagan Teki }
30277b8d048SJagan Teki /* Disable the channel */
30377b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
30477b8d048SJagan Teki
30577b8d048SJagan Teki /*if transfer must be terminated disable the channel*/
30677b8d048SJagan Teki if (flags & SPI_XFER_END) {
30777b8d048SJagan Teki chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
30877b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
30977b8d048SJagan Teki }
31077b8d048SJagan Teki
31177b8d048SJagan Teki return 0;
31277b8d048SJagan Teki }
31377b8d048SJagan Teki
_spi_xfer(struct omap3_spi_priv * priv,unsigned int bitlen,const void * dout,void * din,unsigned long flags)31477b8d048SJagan Teki static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen,
31577b8d048SJagan Teki const void *dout, void *din, unsigned long flags)
31677b8d048SJagan Teki {
31777b8d048SJagan Teki unsigned int len;
31877b8d048SJagan Teki int ret = -1;
31977b8d048SJagan Teki
32077b8d048SJagan Teki if (priv->wordlen < 4 || priv->wordlen > 32) {
32177b8d048SJagan Teki printf("omap3_spi: invalid wordlen %d\n", priv->wordlen);
32277b8d048SJagan Teki return -1;
32377b8d048SJagan Teki }
32477b8d048SJagan Teki
32577b8d048SJagan Teki if (bitlen % priv->wordlen)
32677b8d048SJagan Teki return -1;
32777b8d048SJagan Teki
32877b8d048SJagan Teki len = bitlen / priv->wordlen;
32977b8d048SJagan Teki
33077b8d048SJagan Teki if (bitlen == 0) { /* only change CS */
33177b8d048SJagan Teki int chconf = readl(&priv->regs->channel[priv->cs].chconf);
33277b8d048SJagan Teki
33377b8d048SJagan Teki if (flags & SPI_XFER_BEGIN) {
33477b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN);
33577b8d048SJagan Teki chconf |= OMAP3_MCSPI_CHCONF_FORCE;
33677b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
33777b8d048SJagan Teki }
33877b8d048SJagan Teki if (flags & SPI_XFER_END) {
33977b8d048SJagan Teki chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
34077b8d048SJagan Teki omap3_spi_write_chconf(priv, chconf);
34177b8d048SJagan Teki omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS);
34277b8d048SJagan Teki }
34377b8d048SJagan Teki ret = 0;
34477b8d048SJagan Teki } else {
34577b8d048SJagan Teki if (dout != NULL && din != NULL)
34677b8d048SJagan Teki ret = omap3_spi_txrx(priv, len, dout, din, flags);
34777b8d048SJagan Teki else if (dout != NULL)
34877b8d048SJagan Teki ret = omap3_spi_write(priv, len, dout, flags);
34977b8d048SJagan Teki else if (din != NULL)
35077b8d048SJagan Teki ret = omap3_spi_read(priv, len, din, flags);
35177b8d048SJagan Teki }
35277b8d048SJagan Teki return ret;
35377b8d048SJagan Teki }
35477b8d048SJagan Teki
_omap3_spi_set_speed(struct omap3_spi_priv * priv)35577b8d048SJagan Teki static void _omap3_spi_set_speed(struct omap3_spi_priv *priv)
35677b8d048SJagan Teki {
35777b8d048SJagan Teki uint32_t confr, div = 0;
35877b8d048SJagan Teki
35977b8d048SJagan Teki confr = readl(&priv->regs->channel[priv->cs].chconf);
36077b8d048SJagan Teki
36177b8d048SJagan Teki /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
36277b8d048SJagan Teki if (priv->freq) {
36377b8d048SJagan Teki while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
36477b8d048SJagan Teki > priv->freq)
36577b8d048SJagan Teki div++;
36677b8d048SJagan Teki } else {
36777b8d048SJagan Teki div = 0xC;
36877b8d048SJagan Teki }
36977b8d048SJagan Teki
37077b8d048SJagan Teki /* set clock divisor */
37177b8d048SJagan Teki confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
37277b8d048SJagan Teki confr |= div << 2;
37377b8d048SJagan Teki
37477b8d048SJagan Teki omap3_spi_write_chconf(priv, confr);
37577b8d048SJagan Teki }
37677b8d048SJagan Teki
_omap3_spi_set_mode(struct omap3_spi_priv * priv)37777b8d048SJagan Teki static void _omap3_spi_set_mode(struct omap3_spi_priv *priv)
37877b8d048SJagan Teki {
37977b8d048SJagan Teki uint32_t confr;
38077b8d048SJagan Teki
38177b8d048SJagan Teki confr = readl(&priv->regs->channel[priv->cs].chconf);
38277b8d048SJagan Teki
38377b8d048SJagan Teki /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
38477b8d048SJagan Teki * REVISIT: this controller could support SPI_3WIRE mode.
38577b8d048SJagan Teki */
38677b8d048SJagan Teki if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
38777b8d048SJagan Teki confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
38877b8d048SJagan Teki confr |= OMAP3_MCSPI_CHCONF_DPE0;
38977b8d048SJagan Teki } else {
39077b8d048SJagan Teki confr &= ~OMAP3_MCSPI_CHCONF_DPE0;
39177b8d048SJagan Teki confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
39277b8d048SJagan Teki }
39377b8d048SJagan Teki
39477b8d048SJagan Teki /* set SPI mode 0..3 */
39577b8d048SJagan Teki confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA);
39677b8d048SJagan Teki if (priv->mode & SPI_CPHA)
39777b8d048SJagan Teki confr |= OMAP3_MCSPI_CHCONF_PHA;
39877b8d048SJagan Teki if (priv->mode & SPI_CPOL)
39977b8d048SJagan Teki confr |= OMAP3_MCSPI_CHCONF_POL;
40077b8d048SJagan Teki
40177b8d048SJagan Teki /* set chipselect polarity; manage with FORCE */
40277b8d048SJagan Teki if (!(priv->mode & SPI_CS_HIGH))
40377b8d048SJagan Teki confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
40477b8d048SJagan Teki else
40577b8d048SJagan Teki confr &= ~OMAP3_MCSPI_CHCONF_EPOL;
40677b8d048SJagan Teki
40777b8d048SJagan Teki /* Transmit & receive mode */
40877b8d048SJagan Teki confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
40977b8d048SJagan Teki
41077b8d048SJagan Teki omap3_spi_write_chconf(priv, confr);
41177b8d048SJagan Teki }
41277b8d048SJagan Teki
_omap3_spi_set_wordlen(struct omap3_spi_priv * priv)41377b8d048SJagan Teki static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv)
41477b8d048SJagan Teki {
41577b8d048SJagan Teki unsigned int confr;
41677b8d048SJagan Teki
41777b8d048SJagan Teki /* McSPI individual channel configuration */
418*b8b88e6aSDavid Rivshin confr = readl(&priv->regs->channel[priv->cs].chconf);
41977b8d048SJagan Teki
42077b8d048SJagan Teki /* wordlength */
42177b8d048SJagan Teki confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
42277b8d048SJagan Teki confr |= (priv->wordlen - 1) << 7;
42377b8d048SJagan Teki
42477b8d048SJagan Teki omap3_spi_write_chconf(priv, confr);
42577b8d048SJagan Teki }
42677b8d048SJagan Teki
spi_reset(struct mcspi * regs)42777b8d048SJagan Teki static void spi_reset(struct mcspi *regs)
42877b8d048SJagan Teki {
42977b8d048SJagan Teki unsigned int tmp;
43077b8d048SJagan Teki
43177b8d048SJagan Teki writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, ®s->sysconfig);
43277b8d048SJagan Teki do {
43377b8d048SJagan Teki tmp = readl(®s->sysstatus);
43477b8d048SJagan Teki } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
43577b8d048SJagan Teki
43677b8d048SJagan Teki writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
43777b8d048SJagan Teki OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
43877b8d048SJagan Teki OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, ®s->sysconfig);
43977b8d048SJagan Teki
44077b8d048SJagan Teki writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, ®s->wakeupenable);
44177b8d048SJagan Teki }
44277b8d048SJagan Teki
_omap3_spi_claim_bus(struct omap3_spi_priv * priv)44377b8d048SJagan Teki static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv)
44477b8d048SJagan Teki {
44577b8d048SJagan Teki unsigned int conf;
44677b8d048SJagan Teki /*
44777b8d048SJagan Teki * setup when switching from (reset default) slave mode
44877b8d048SJagan Teki * to single-channel master mode
44977b8d048SJagan Teki */
45077b8d048SJagan Teki conf = readl(&priv->regs->modulctrl);
45177b8d048SJagan Teki conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
45277b8d048SJagan Teki conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
45377b8d048SJagan Teki
45477b8d048SJagan Teki writel(conf, &priv->regs->modulctrl);
45577b8d048SJagan Teki }
45677b8d048SJagan Teki
45777b8d048SJagan Teki #ifndef CONFIG_DM_SPI
45877b8d048SJagan Teki
to_omap3_spi(struct spi_slave * slave)45941bccb81SJagan Teki static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave)
460682c1723SJagan Teki {
46141bccb81SJagan Teki return container_of(slave, struct omap3_spi_priv, slave);
462682c1723SJagan Teki }
463682c1723SJagan Teki
spi_free_slave(struct spi_slave * slave)46477b8d048SJagan Teki void spi_free_slave(struct spi_slave *slave)
46577b8d048SJagan Teki {
46641bccb81SJagan Teki struct omap3_spi_priv *priv = to_omap3_spi(slave);
46777b8d048SJagan Teki
46841bccb81SJagan Teki free(priv);
46977b8d048SJagan Teki }
47077b8d048SJagan Teki
spi_claim_bus(struct spi_slave * slave)47177b8d048SJagan Teki int spi_claim_bus(struct spi_slave *slave)
47277b8d048SJagan Teki {
47341bccb81SJagan Teki struct omap3_spi_priv *priv = to_omap3_spi(slave);
47441bccb81SJagan Teki
475c0eaffa0SHannes Schmelzer spi_reset(priv->regs);
476c0eaffa0SHannes Schmelzer
47777b8d048SJagan Teki _omap3_spi_claim_bus(priv);
47877b8d048SJagan Teki _omap3_spi_set_wordlen(priv);
47977b8d048SJagan Teki _omap3_spi_set_mode(priv);
48077b8d048SJagan Teki _omap3_spi_set_speed(priv);
48177b8d048SJagan Teki
48277b8d048SJagan Teki return 0;
48377b8d048SJagan Teki }
48477b8d048SJagan Teki
spi_release_bus(struct spi_slave * slave)48577b8d048SJagan Teki void spi_release_bus(struct spi_slave *slave)
48677b8d048SJagan Teki {
48741bccb81SJagan Teki struct omap3_spi_priv *priv = to_omap3_spi(slave);
48841bccb81SJagan Teki
489c0eaffa0SHannes Schmelzer writel(OMAP3_MCSPI_MODULCTRL_MS, &priv->regs->modulctrl);
49077b8d048SJagan Teki }
49177b8d048SJagan Teki
spi_setup_slave(unsigned int bus,unsigned int cs,unsigned int max_hz,unsigned int mode)49253736baaSDirk Behme struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
49353736baaSDirk Behme unsigned int max_hz, unsigned int mode)
49453736baaSDirk Behme {
49541bccb81SJagan Teki struct omap3_spi_priv *priv;
496d3504feeSSimon Glass struct mcspi *regs;
49753736baaSDirk Behme
49853736baaSDirk Behme /*
49953736baaSDirk Behme * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
50053736baaSDirk Behme * with different number of chip selects (CS, channels):
50153736baaSDirk Behme * McSPI1 has 4 CS (bus 0, cs 0 - 3)
50253736baaSDirk Behme * McSPI2 has 2 CS (bus 1, cs 0 - 1)
50353736baaSDirk Behme * McSPI3 has 2 CS (bus 2, cs 0 - 1)
50453736baaSDirk Behme * McSPI4 has 1 CS (bus 3, cs 0)
50553736baaSDirk Behme */
50653736baaSDirk Behme
50753736baaSDirk Behme switch (bus) {
50853736baaSDirk Behme case 0:
509d3504feeSSimon Glass regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
51053736baaSDirk Behme break;
5114c0620bfSTom Rini #ifdef OMAP3_MCSPI2_BASE
51253736baaSDirk Behme case 1:
513d3504feeSSimon Glass regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
51453736baaSDirk Behme break;
5154c0620bfSTom Rini #endif
5164c0620bfSTom Rini #ifdef OMAP3_MCSPI3_BASE
51753736baaSDirk Behme case 2:
518d3504feeSSimon Glass regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
51953736baaSDirk Behme break;
5204c0620bfSTom Rini #endif
5214c0620bfSTom Rini #ifdef OMAP3_MCSPI4_BASE
52253736baaSDirk Behme case 3:
523d3504feeSSimon Glass regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
52453736baaSDirk Behme break;
5254c0620bfSTom Rini #endif
52653736baaSDirk Behme default:
52777b8d048SJagan Teki printf("SPI error: unsupported bus %i. Supported busses 0 - 3\n", bus);
52853736baaSDirk Behme return NULL;
52953736baaSDirk Behme }
53053736baaSDirk Behme
53153736baaSDirk Behme if (((bus == 0) && (cs > 3)) ||
53253736baaSDirk Behme ((bus == 1) && (cs > 1)) ||
53353736baaSDirk Behme ((bus == 2) && (cs > 1)) ||
53453736baaSDirk Behme ((bus == 3) && (cs > 0))) {
53577b8d048SJagan Teki printf("SPI error: unsupported chip select %i on bus %i\n", cs, bus);
53653736baaSDirk Behme return NULL;
53753736baaSDirk Behme }
53853736baaSDirk Behme
53953736baaSDirk Behme if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
540042de609SHeinrich Schuchardt printf("SPI error: unsupported frequency %i Hz. Max frequency is 48 MHz\n",
541042de609SHeinrich Schuchardt max_hz);
54253736baaSDirk Behme return NULL;
54353736baaSDirk Behme }
54453736baaSDirk Behme
54553736baaSDirk Behme if (mode > SPI_MODE_3) {
54653736baaSDirk Behme printf("SPI error: unsupported SPI mode %i\n", mode);
54753736baaSDirk Behme return NULL;
54853736baaSDirk Behme }
549d3504feeSSimon Glass
55041bccb81SJagan Teki priv = spi_alloc_slave(struct omap3_spi_priv, bus, cs);
55141bccb81SJagan Teki if (!priv) {
552d3504feeSSimon Glass printf("SPI error: malloc of SPI structure failed\n");
553d3504feeSSimon Glass return NULL;
554d3504feeSSimon Glass }
555d3504feeSSimon Glass
55677b8d048SJagan Teki priv->regs = regs;
55777b8d048SJagan Teki priv->cs = cs;
55877b8d048SJagan Teki priv->freq = max_hz;
55977b8d048SJagan Teki priv->mode = mode;
56041bccb81SJagan Teki priv->wordlen = priv->slave.wordlen;
56125eaa288STom Rini #if 0
56225eaa288STom Rini /* Please migrate to DM_SPI support for this feature. */
56377b8d048SJagan Teki priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
56477b8d048SJagan Teki #endif
56553736baaSDirk Behme
56641bccb81SJagan Teki return &priv->slave;
56753736baaSDirk Behme }
56853736baaSDirk Behme
spi_xfer(struct spi_slave * slave,unsigned int bitlen,const void * dout,void * din,unsigned long flags)56953736baaSDirk Behme int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
57053736baaSDirk Behme const void *dout, void *din, unsigned long flags)
57141bccb81SJagan Teki {
57241bccb81SJagan Teki struct omap3_spi_priv *priv = to_omap3_spi(slave);
57341bccb81SJagan Teki
57441bccb81SJagan Teki return _spi_xfer(priv, bitlen, dout, din, flags);
57541bccb81SJagan Teki }
57677b8d048SJagan Teki
57777b8d048SJagan Teki #else
57877b8d048SJagan Teki
omap3_spi_claim_bus(struct udevice * dev)57977b8d048SJagan Teki static int omap3_spi_claim_bus(struct udevice *dev)
58053736baaSDirk Behme {
58177b8d048SJagan Teki struct udevice *bus = dev->parent;
58277b8d048SJagan Teki struct omap3_spi_priv *priv = dev_get_priv(bus);
58377b8d048SJagan Teki struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
58453736baaSDirk Behme
58577b8d048SJagan Teki priv->cs = slave_plat->cs;
586b1d2b529SHannes Schmelzer priv->freq = slave_plat->max_hz;
587b1d2b529SHannes Schmelzer
58877b8d048SJagan Teki _omap3_spi_claim_bus(priv);
58977b8d048SJagan Teki
59077b8d048SJagan Teki return 0;
5915753d09bSNikita Kiryanov }
5925753d09bSNikita Kiryanov
omap3_spi_release_bus(struct udevice * dev)59377b8d048SJagan Teki static int omap3_spi_release_bus(struct udevice *dev)
59453736baaSDirk Behme {
59577b8d048SJagan Teki struct udevice *bus = dev->parent;
59677b8d048SJagan Teki struct omap3_spi_priv *priv = dev_get_priv(bus);
59777b8d048SJagan Teki
598c0eaffa0SHannes Schmelzer writel(OMAP3_MCSPI_MODULCTRL_MS, &priv->regs->modulctrl);
59977b8d048SJagan Teki
60077b8d048SJagan Teki return 0;
60153736baaSDirk Behme }
60253736baaSDirk Behme
omap3_spi_set_wordlen(struct udevice * dev,unsigned int wordlen)60377b8d048SJagan Teki static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
60453736baaSDirk Behme {
60577b8d048SJagan Teki struct udevice *bus = dev->parent;
60677b8d048SJagan Teki struct omap3_spi_priv *priv = dev_get_priv(bus);
60777b8d048SJagan Teki struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
60877b8d048SJagan Teki
60977b8d048SJagan Teki priv->cs = slave_plat->cs;
61077b8d048SJagan Teki priv->wordlen = wordlen;
61177b8d048SJagan Teki _omap3_spi_set_wordlen(priv);
61277b8d048SJagan Teki
61377b8d048SJagan Teki return 0;
61453736baaSDirk Behme }
61553736baaSDirk Behme
omap3_spi_probe(struct udevice * dev)61677b8d048SJagan Teki static int omap3_spi_probe(struct udevice *dev)
61753736baaSDirk Behme {
61877b8d048SJagan Teki struct omap3_spi_priv *priv = dev_get_priv(dev);
61977b8d048SJagan Teki const void *blob = gd->fdt_blob;
620e160f7d4SSimon Glass int node = dev_of_offset(dev);
62177b8d048SJagan Teki
6225f89a15eSMartin Hejnfelt struct omap2_mcspi_platform_config* data =
6235f89a15eSMartin Hejnfelt (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
6245f89a15eSMartin Hejnfelt
625a821c4afSSimon Glass priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset);
62663018a3eSSjoerd Simons if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
62763018a3eSSjoerd Simons priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
62863018a3eSSjoerd Simons else
62963018a3eSSjoerd Simons priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
63077b8d048SJagan Teki priv->wordlen = SPI_DEFAULT_WORDLEN;
631c0eaffa0SHannes Schmelzer
632c0eaffa0SHannes Schmelzer spi_reset(priv->regs);
633c0eaffa0SHannes Schmelzer
63477b8d048SJagan Teki return 0;
63553736baaSDirk Behme }
63677b8d048SJagan Teki
omap3_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)63777b8d048SJagan Teki static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen,
63877b8d048SJagan Teki const void *dout, void *din, unsigned long flags)
63977b8d048SJagan Teki {
64077b8d048SJagan Teki struct udevice *bus = dev->parent;
64177b8d048SJagan Teki struct omap3_spi_priv *priv = dev_get_priv(bus);
64277b8d048SJagan Teki
64377b8d048SJagan Teki return _spi_xfer(priv, bitlen, dout, din, flags);
64477b8d048SJagan Teki }
64577b8d048SJagan Teki
omap3_spi_set_speed(struct udevice * dev,unsigned int speed)646b2b41d27SJagan Teki static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed)
64777b8d048SJagan Teki {
64884807922SJagan Teki
6499cddf70eSHannes Schmelzer struct omap3_spi_priv *priv = dev_get_priv(dev);
6509cddf70eSHannes Schmelzer
6519cddf70eSHannes Schmelzer priv->freq = speed;
65284807922SJagan Teki _omap3_spi_set_speed(priv);
65384807922SJagan Teki
65477b8d048SJagan Teki return 0;
65577b8d048SJagan Teki }
65677b8d048SJagan Teki
omap3_spi_set_mode(struct udevice * dev,uint mode)657b2b41d27SJagan Teki static int omap3_spi_set_mode(struct udevice *dev, uint mode)
65877b8d048SJagan Teki {
6599cddf70eSHannes Schmelzer struct omap3_spi_priv *priv = dev_get_priv(dev);
66084807922SJagan Teki
6619cddf70eSHannes Schmelzer priv->mode = mode;
6629cddf70eSHannes Schmelzer
66384807922SJagan Teki _omap3_spi_set_mode(priv);
66484807922SJagan Teki
66577b8d048SJagan Teki return 0;
66677b8d048SJagan Teki }
66777b8d048SJagan Teki
66877b8d048SJagan Teki static const struct dm_spi_ops omap3_spi_ops = {
66977b8d048SJagan Teki .claim_bus = omap3_spi_claim_bus,
67077b8d048SJagan Teki .release_bus = omap3_spi_release_bus,
67177b8d048SJagan Teki .set_wordlen = omap3_spi_set_wordlen,
67277b8d048SJagan Teki .xfer = omap3_spi_xfer,
67377b8d048SJagan Teki .set_speed = omap3_spi_set_speed,
67477b8d048SJagan Teki .set_mode = omap3_spi_set_mode,
67577b8d048SJagan Teki /*
67677b8d048SJagan Teki * cs_info is not needed, since we require all chip selects to be
67777b8d048SJagan Teki * in the device tree explicitly
67877b8d048SJagan Teki */
67977b8d048SJagan Teki };
68077b8d048SJagan Teki
6815f89a15eSMartin Hejnfelt static struct omap2_mcspi_platform_config omap2_pdata = {
6825f89a15eSMartin Hejnfelt .regs_offset = 0,
6835f89a15eSMartin Hejnfelt };
6845f89a15eSMartin Hejnfelt
6855f89a15eSMartin Hejnfelt static struct omap2_mcspi_platform_config omap4_pdata = {
6865f89a15eSMartin Hejnfelt .regs_offset = OMAP4_MCSPI_REG_OFFSET,
6875f89a15eSMartin Hejnfelt };
6885f89a15eSMartin Hejnfelt
68977b8d048SJagan Teki static const struct udevice_id omap3_spi_ids[] = {
6905f89a15eSMartin Hejnfelt { .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata },
6915f89a15eSMartin Hejnfelt { .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata },
69277b8d048SJagan Teki { }
69377b8d048SJagan Teki };
69477b8d048SJagan Teki
69577b8d048SJagan Teki U_BOOT_DRIVER(omap3_spi) = {
69677b8d048SJagan Teki .name = "omap3_spi",
69777b8d048SJagan Teki .id = UCLASS_SPI,
69877b8d048SJagan Teki .of_match = omap3_spi_ids,
69977b8d048SJagan Teki .probe = omap3_spi_probe,
70077b8d048SJagan Teki .ops = &omap3_spi_ops,
70177b8d048SJagan Teki .priv_auto_alloc_size = sizeof(struct omap3_spi_priv),
70277b8d048SJagan Teki };
70377b8d048SJagan Teki #endif
704