Commit c0eaffa03959a97e6c139ea023e4041170e105e6
Committed by
Jagan Teki
1 parent
51dce7d2bf
Exists in
smarc_8mq_lf_v2020.04
and in
12 other branches
spi: omap3: fix claim/release bus within DM
The claim/release bus function must not reset the whole SPI core because settings regarding wordlen, clock-frequency and so on made by set_wordlen, set_mode, set_speed get lost with this action. Resulting in a non-functional SPI. Without DM the failure didn't came up since after the spi_reset within claim bus all the setup (wordlen, mode, ...) was called, in DM they are called by the spi uclass. We change now the things as following for having a working SPI instance in DM: - move the spi_reset(...) to the probe call in DM for having a known hardware state after probe. Without DM we don't have a probe call, so we issue the reset as before during the claim_bus call. - in release bus we just reset the modulctrl to the reset-value (spi- slave) Signed-off-by: Hannes Schmelzer <oe5hpm@oevsv.at> Reviewed-by: Jagan Teki <jagan@openedev.com>
Showing 1 changed file with 7 additions and 7 deletions Inline Diff
drivers/spi/omap3_spi.c
1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | 2 | /* |
3 | * Copyright (C) 2016 Jagan Teki <jteki@openedev.com> | 3 | * Copyright (C) 2016 Jagan Teki <jteki@openedev.com> |
4 | * Christophe Ricard <christophe.ricard@gmail.com> | 4 | * Christophe Ricard <christophe.ricard@gmail.com> |
5 | * | 5 | * |
6 | * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com> | 6 | * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com> |
7 | * | 7 | * |
8 | * Driver for McSPI controller on OMAP3. Based on davinci_spi.c | 8 | * Driver for McSPI controller on OMAP3. Based on davinci_spi.c |
9 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | 9 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ |
10 | * | 10 | * |
11 | * Copyright (C) 2007 Atmel Corporation | 11 | * Copyright (C) 2007 Atmel Corporation |
12 | * | 12 | * |
13 | * Parts taken from linux/drivers/spi/omap2_mcspi.c | 13 | * Parts taken from linux/drivers/spi/omap2_mcspi.c |
14 | * Copyright (C) 2005, 2006 Nokia Corporation | 14 | * Copyright (C) 2005, 2006 Nokia Corporation |
15 | * | 15 | * |
16 | * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com> | 16 | * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com> |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <common.h> | 19 | #include <common.h> |
20 | #include <dm.h> | 20 | #include <dm.h> |
21 | #include <spi.h> | 21 | #include <spi.h> |
22 | #include <malloc.h> | 22 | #include <malloc.h> |
23 | #include <asm/io.h> | 23 | #include <asm/io.h> |
24 | 24 | ||
25 | DECLARE_GLOBAL_DATA_PTR; | 25 | DECLARE_GLOBAL_DATA_PTR; |
26 | 26 | ||
27 | #if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) | 27 | #if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX) |
28 | #define OMAP3_MCSPI1_BASE 0x48030100 | 28 | #define OMAP3_MCSPI1_BASE 0x48030100 |
29 | #define OMAP3_MCSPI2_BASE 0x481A0100 | 29 | #define OMAP3_MCSPI2_BASE 0x481A0100 |
30 | #else | 30 | #else |
31 | #define OMAP3_MCSPI1_BASE 0x48098000 | 31 | #define OMAP3_MCSPI1_BASE 0x48098000 |
32 | #define OMAP3_MCSPI2_BASE 0x4809A000 | 32 | #define OMAP3_MCSPI2_BASE 0x4809A000 |
33 | #define OMAP3_MCSPI3_BASE 0x480B8000 | 33 | #define OMAP3_MCSPI3_BASE 0x480B8000 |
34 | #define OMAP3_MCSPI4_BASE 0x480BA000 | 34 | #define OMAP3_MCSPI4_BASE 0x480BA000 |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #define OMAP4_MCSPI_REG_OFFSET 0x100 | 37 | #define OMAP4_MCSPI_REG_OFFSET 0x100 |
38 | 38 | ||
39 | struct omap2_mcspi_platform_config { | 39 | struct omap2_mcspi_platform_config { |
40 | unsigned int regs_offset; | 40 | unsigned int regs_offset; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* per-register bitmasks */ | 43 | /* per-register bitmasks */ |
44 | #define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3) | 44 | #define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3) |
45 | #define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2) | 45 | #define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2) |
46 | #define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0) | 46 | #define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE BIT(0) |
47 | #define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1) | 47 | #define OMAP3_MCSPI_SYSCONFIG_SOFTRESET BIT(1) |
48 | 48 | ||
49 | #define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0) | 49 | #define OMAP3_MCSPI_SYSSTATUS_RESETDONE BIT(0) |
50 | 50 | ||
51 | #define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0) | 51 | #define OMAP3_MCSPI_MODULCTRL_SINGLE BIT(0) |
52 | #define OMAP3_MCSPI_MODULCTRL_MS BIT(2) | 52 | #define OMAP3_MCSPI_MODULCTRL_MS BIT(2) |
53 | #define OMAP3_MCSPI_MODULCTRL_STEST BIT(3) | 53 | #define OMAP3_MCSPI_MODULCTRL_STEST BIT(3) |
54 | 54 | ||
55 | #define OMAP3_MCSPI_CHCONF_PHA BIT(0) | 55 | #define OMAP3_MCSPI_CHCONF_PHA BIT(0) |
56 | #define OMAP3_MCSPI_CHCONF_POL BIT(1) | 56 | #define OMAP3_MCSPI_CHCONF_POL BIT(1) |
57 | #define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2) | 57 | #define OMAP3_MCSPI_CHCONF_CLKD_MASK GENMASK(5, 2) |
58 | #define OMAP3_MCSPI_CHCONF_EPOL BIT(6) | 58 | #define OMAP3_MCSPI_CHCONF_EPOL BIT(6) |
59 | #define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7) | 59 | #define OMAP3_MCSPI_CHCONF_WL_MASK GENMASK(11, 7) |
60 | #define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) | 60 | #define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) |
61 | #define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) | 61 | #define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) |
62 | #define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12) | 62 | #define OMAP3_MCSPI_CHCONF_TRM_MASK GENMASK(13, 12) |
63 | #define OMAP3_MCSPI_CHCONF_DMAW BIT(14) | 63 | #define OMAP3_MCSPI_CHCONF_DMAW BIT(14) |
64 | #define OMAP3_MCSPI_CHCONF_DMAR BIT(15) | 64 | #define OMAP3_MCSPI_CHCONF_DMAR BIT(15) |
65 | #define OMAP3_MCSPI_CHCONF_DPE0 BIT(16) | 65 | #define OMAP3_MCSPI_CHCONF_DPE0 BIT(16) |
66 | #define OMAP3_MCSPI_CHCONF_DPE1 BIT(17) | 66 | #define OMAP3_MCSPI_CHCONF_DPE1 BIT(17) |
67 | #define OMAP3_MCSPI_CHCONF_IS BIT(18) | 67 | #define OMAP3_MCSPI_CHCONF_IS BIT(18) |
68 | #define OMAP3_MCSPI_CHCONF_TURBO BIT(19) | 68 | #define OMAP3_MCSPI_CHCONF_TURBO BIT(19) |
69 | #define OMAP3_MCSPI_CHCONF_FORCE BIT(20) | 69 | #define OMAP3_MCSPI_CHCONF_FORCE BIT(20) |
70 | 70 | ||
71 | #define OMAP3_MCSPI_CHSTAT_RXS BIT(0) | 71 | #define OMAP3_MCSPI_CHSTAT_RXS BIT(0) |
72 | #define OMAP3_MCSPI_CHSTAT_TXS BIT(1) | 72 | #define OMAP3_MCSPI_CHSTAT_TXS BIT(1) |
73 | #define OMAP3_MCSPI_CHSTAT_EOT BIT(2) | 73 | #define OMAP3_MCSPI_CHSTAT_EOT BIT(2) |
74 | 74 | ||
75 | #define OMAP3_MCSPI_CHCTRL_EN BIT(0) | 75 | #define OMAP3_MCSPI_CHCTRL_EN BIT(0) |
76 | #define OMAP3_MCSPI_CHCTRL_DIS (0 << 0) | 76 | #define OMAP3_MCSPI_CHCTRL_DIS (0 << 0) |
77 | 77 | ||
78 | #define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0) | 78 | #define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0) |
79 | #define MCSPI_PINDIR_D0_IN_D1_OUT 0 | 79 | #define MCSPI_PINDIR_D0_IN_D1_OUT 0 |
80 | #define MCSPI_PINDIR_D0_OUT_D1_IN 1 | 80 | #define MCSPI_PINDIR_D0_OUT_D1_IN 1 |
81 | 81 | ||
82 | #define OMAP3_MCSPI_MAX_FREQ 48000000 | 82 | #define OMAP3_MCSPI_MAX_FREQ 48000000 |
83 | #define SPI_WAIT_TIMEOUT 10 | 83 | #define SPI_WAIT_TIMEOUT 10 |
84 | 84 | ||
85 | /* OMAP3 McSPI registers */ | 85 | /* OMAP3 McSPI registers */ |
86 | struct mcspi_channel { | 86 | struct mcspi_channel { |
87 | unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */ | 87 | unsigned int chconf; /* 0x2C, 0x40, 0x54, 0x68 */ |
88 | unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */ | 88 | unsigned int chstat; /* 0x30, 0x44, 0x58, 0x6C */ |
89 | unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */ | 89 | unsigned int chctrl; /* 0x34, 0x48, 0x5C, 0x70 */ |
90 | unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */ | 90 | unsigned int tx; /* 0x38, 0x4C, 0x60, 0x74 */ |
91 | unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */ | 91 | unsigned int rx; /* 0x3C, 0x50, 0x64, 0x78 */ |
92 | }; | 92 | }; |
93 | 93 | ||
94 | struct mcspi { | 94 | struct mcspi { |
95 | unsigned char res1[0x10]; | 95 | unsigned char res1[0x10]; |
96 | unsigned int sysconfig; /* 0x10 */ | 96 | unsigned int sysconfig; /* 0x10 */ |
97 | unsigned int sysstatus; /* 0x14 */ | 97 | unsigned int sysstatus; /* 0x14 */ |
98 | unsigned int irqstatus; /* 0x18 */ | 98 | unsigned int irqstatus; /* 0x18 */ |
99 | unsigned int irqenable; /* 0x1C */ | 99 | unsigned int irqenable; /* 0x1C */ |
100 | unsigned int wakeupenable; /* 0x20 */ | 100 | unsigned int wakeupenable; /* 0x20 */ |
101 | unsigned int syst; /* 0x24 */ | 101 | unsigned int syst; /* 0x24 */ |
102 | unsigned int modulctrl; /* 0x28 */ | 102 | unsigned int modulctrl; /* 0x28 */ |
103 | struct mcspi_channel channel[4]; | 103 | struct mcspi_channel channel[4]; |
104 | /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */ | 104 | /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */ |
105 | /* channel1: 0x40 - 0x50, bus 0 & 1 */ | 105 | /* channel1: 0x40 - 0x50, bus 0 & 1 */ |
106 | /* channel2: 0x54 - 0x64, bus 0 & 1 */ | 106 | /* channel2: 0x54 - 0x64, bus 0 & 1 */ |
107 | /* channel3: 0x68 - 0x78, bus 0 */ | 107 | /* channel3: 0x68 - 0x78, bus 0 */ |
108 | }; | 108 | }; |
109 | 109 | ||
110 | struct omap3_spi_priv { | 110 | struct omap3_spi_priv { |
111 | #ifndef CONFIG_DM_SPI | 111 | #ifndef CONFIG_DM_SPI |
112 | struct spi_slave slave; | 112 | struct spi_slave slave; |
113 | #endif | 113 | #endif |
114 | struct mcspi *regs; | 114 | struct mcspi *regs; |
115 | unsigned int cs; | 115 | unsigned int cs; |
116 | unsigned int freq; | 116 | unsigned int freq; |
117 | unsigned int mode; | 117 | unsigned int mode; |
118 | unsigned int wordlen; | 118 | unsigned int wordlen; |
119 | unsigned int pin_dir:1; | 119 | unsigned int pin_dir:1; |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val) | 122 | static void omap3_spi_write_chconf(struct omap3_spi_priv *priv, int val) |
123 | { | 123 | { |
124 | writel(val, &priv->regs->channel[priv->cs].chconf); | 124 | writel(val, &priv->regs->channel[priv->cs].chconf); |
125 | /* Flash post writes to make immediate effect */ | 125 | /* Flash post writes to make immediate effect */ |
126 | readl(&priv->regs->channel[priv->cs].chconf); | 126 | readl(&priv->regs->channel[priv->cs].chconf); |
127 | } | 127 | } |
128 | 128 | ||
129 | static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable) | 129 | static void omap3_spi_set_enable(struct omap3_spi_priv *priv, int enable) |
130 | { | 130 | { |
131 | writel(enable, &priv->regs->channel[priv->cs].chctrl); | 131 | writel(enable, &priv->regs->channel[priv->cs].chctrl); |
132 | /* Flash post writes to make immediate effect */ | 132 | /* Flash post writes to make immediate effect */ |
133 | readl(&priv->regs->channel[priv->cs].chctrl); | 133 | readl(&priv->regs->channel[priv->cs].chctrl); |
134 | } | 134 | } |
135 | 135 | ||
136 | static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len, | 136 | static int omap3_spi_write(struct omap3_spi_priv *priv, unsigned int len, |
137 | const void *txp, unsigned long flags) | 137 | const void *txp, unsigned long flags) |
138 | { | 138 | { |
139 | ulong start; | 139 | ulong start; |
140 | int i, chconf; | 140 | int i, chconf; |
141 | 141 | ||
142 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | 142 | chconf = readl(&priv->regs->channel[priv->cs].chconf); |
143 | 143 | ||
144 | /* Enable the channel */ | 144 | /* Enable the channel */ |
145 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | 145 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
146 | 146 | ||
147 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | 147 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
148 | chconf |= (priv->wordlen - 1) << 7; | 148 | chconf |= (priv->wordlen - 1) << 7; |
149 | chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; | 149 | chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; |
150 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | 150 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
151 | omap3_spi_write_chconf(priv, chconf); | 151 | omap3_spi_write_chconf(priv, chconf); |
152 | 152 | ||
153 | for (i = 0; i < len; i++) { | 153 | for (i = 0; i < len; i++) { |
154 | /* wait till TX register is empty (TXS == 1) */ | 154 | /* wait till TX register is empty (TXS == 1) */ |
155 | start = get_timer(0); | 155 | start = get_timer(0); |
156 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & | 156 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
157 | OMAP3_MCSPI_CHSTAT_TXS)) { | 157 | OMAP3_MCSPI_CHSTAT_TXS)) { |
158 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { | 158 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
159 | printf("SPI TXS timed out, status=0x%08x\n", | 159 | printf("SPI TXS timed out, status=0x%08x\n", |
160 | readl(&priv->regs->channel[priv->cs].chstat)); | 160 | readl(&priv->regs->channel[priv->cs].chstat)); |
161 | return -1; | 161 | return -1; |
162 | } | 162 | } |
163 | } | 163 | } |
164 | /* Write the data */ | 164 | /* Write the data */ |
165 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; | 165 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; |
166 | if (priv->wordlen > 16) | 166 | if (priv->wordlen > 16) |
167 | writel(((u32 *)txp)[i], tx); | 167 | writel(((u32 *)txp)[i], tx); |
168 | else if (priv->wordlen > 8) | 168 | else if (priv->wordlen > 8) |
169 | writel(((u16 *)txp)[i], tx); | 169 | writel(((u16 *)txp)[i], tx); |
170 | else | 170 | else |
171 | writel(((u8 *)txp)[i], tx); | 171 | writel(((u8 *)txp)[i], tx); |
172 | } | 172 | } |
173 | 173 | ||
174 | /* wait to finish of transfer */ | 174 | /* wait to finish of transfer */ |
175 | while ((readl(&priv->regs->channel[priv->cs].chstat) & | 175 | while ((readl(&priv->regs->channel[priv->cs].chstat) & |
176 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) != | 176 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) != |
177 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) | 177 | (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) |
178 | ; | 178 | ; |
179 | 179 | ||
180 | /* Disable the channel otherwise the next immediate RX will get affected */ | 180 | /* Disable the channel otherwise the next immediate RX will get affected */ |
181 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | 181 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
182 | 182 | ||
183 | if (flags & SPI_XFER_END) { | 183 | if (flags & SPI_XFER_END) { |
184 | 184 | ||
185 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | 185 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; |
186 | omap3_spi_write_chconf(priv, chconf); | 186 | omap3_spi_write_chconf(priv, chconf); |
187 | } | 187 | } |
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len, | 191 | static int omap3_spi_read(struct omap3_spi_priv *priv, unsigned int len, |
192 | void *rxp, unsigned long flags) | 192 | void *rxp, unsigned long flags) |
193 | { | 193 | { |
194 | int i, chconf; | 194 | int i, chconf; |
195 | ulong start; | 195 | ulong start; |
196 | 196 | ||
197 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | 197 | chconf = readl(&priv->regs->channel[priv->cs].chconf); |
198 | 198 | ||
199 | /* Enable the channel */ | 199 | /* Enable the channel */ |
200 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | 200 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
201 | 201 | ||
202 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | 202 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
203 | chconf |= (priv->wordlen - 1) << 7; | 203 | chconf |= (priv->wordlen - 1) << 7; |
204 | chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; | 204 | chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; |
205 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | 205 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
206 | omap3_spi_write_chconf(priv, chconf); | 206 | omap3_spi_write_chconf(priv, chconf); |
207 | 207 | ||
208 | writel(0, &priv->regs->channel[priv->cs].tx); | 208 | writel(0, &priv->regs->channel[priv->cs].tx); |
209 | 209 | ||
210 | for (i = 0; i < len; i++) { | 210 | for (i = 0; i < len; i++) { |
211 | start = get_timer(0); | 211 | start = get_timer(0); |
212 | /* Wait till RX register contains data (RXS == 1) */ | 212 | /* Wait till RX register contains data (RXS == 1) */ |
213 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & | 213 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
214 | OMAP3_MCSPI_CHSTAT_RXS)) { | 214 | OMAP3_MCSPI_CHSTAT_RXS)) { |
215 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { | 215 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
216 | printf("SPI RXS timed out, status=0x%08x\n", | 216 | printf("SPI RXS timed out, status=0x%08x\n", |
217 | readl(&priv->regs->channel[priv->cs].chstat)); | 217 | readl(&priv->regs->channel[priv->cs].chstat)); |
218 | return -1; | 218 | return -1; |
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | /* Disable the channel to prevent furher receiving */ | 222 | /* Disable the channel to prevent furher receiving */ |
223 | if (i == (len - 1)) | 223 | if (i == (len - 1)) |
224 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | 224 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
225 | 225 | ||
226 | /* Read the data */ | 226 | /* Read the data */ |
227 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; | 227 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; |
228 | if (priv->wordlen > 16) | 228 | if (priv->wordlen > 16) |
229 | ((u32 *)rxp)[i] = readl(rx); | 229 | ((u32 *)rxp)[i] = readl(rx); |
230 | else if (priv->wordlen > 8) | 230 | else if (priv->wordlen > 8) |
231 | ((u16 *)rxp)[i] = (u16)readl(rx); | 231 | ((u16 *)rxp)[i] = (u16)readl(rx); |
232 | else | 232 | else |
233 | ((u8 *)rxp)[i] = (u8)readl(rx); | 233 | ((u8 *)rxp)[i] = (u8)readl(rx); |
234 | } | 234 | } |
235 | 235 | ||
236 | if (flags & SPI_XFER_END) { | 236 | if (flags & SPI_XFER_END) { |
237 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | 237 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; |
238 | omap3_spi_write_chconf(priv, chconf); | 238 | omap3_spi_write_chconf(priv, chconf); |
239 | } | 239 | } |
240 | 240 | ||
241 | return 0; | 241 | return 0; |
242 | } | 242 | } |
243 | 243 | ||
244 | /*McSPI Transmit Receive Mode*/ | 244 | /*McSPI Transmit Receive Mode*/ |
245 | static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len, | 245 | static int omap3_spi_txrx(struct omap3_spi_priv *priv, unsigned int len, |
246 | const void *txp, void *rxp, unsigned long flags) | 246 | const void *txp, void *rxp, unsigned long flags) |
247 | { | 247 | { |
248 | ulong start; | 248 | ulong start; |
249 | int chconf, i = 0; | 249 | int chconf, i = 0; |
250 | 250 | ||
251 | chconf = readl(&priv->regs->channel[priv->cs].chconf); | 251 | chconf = readl(&priv->regs->channel[priv->cs].chconf); |
252 | 252 | ||
253 | /*Enable SPI channel*/ | 253 | /*Enable SPI channel*/ |
254 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | 254 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
255 | 255 | ||
256 | /*set TRANSMIT-RECEIVE Mode*/ | 256 | /*set TRANSMIT-RECEIVE Mode*/ |
257 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); | 257 | chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); |
258 | chconf |= (priv->wordlen - 1) << 7; | 258 | chconf |= (priv->wordlen - 1) << 7; |
259 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | 259 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
260 | omap3_spi_write_chconf(priv, chconf); | 260 | omap3_spi_write_chconf(priv, chconf); |
261 | 261 | ||
262 | /*Shift in and out 1 byte at time*/ | 262 | /*Shift in and out 1 byte at time*/ |
263 | for (i=0; i < len; i++){ | 263 | for (i=0; i < len; i++){ |
264 | /* Write: wait for TX empty (TXS == 1)*/ | 264 | /* Write: wait for TX empty (TXS == 1)*/ |
265 | start = get_timer(0); | 265 | start = get_timer(0); |
266 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & | 266 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
267 | OMAP3_MCSPI_CHSTAT_TXS)) { | 267 | OMAP3_MCSPI_CHSTAT_TXS)) { |
268 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { | 268 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
269 | printf("SPI TXS timed out, status=0x%08x\n", | 269 | printf("SPI TXS timed out, status=0x%08x\n", |
270 | readl(&priv->regs->channel[priv->cs].chstat)); | 270 | readl(&priv->regs->channel[priv->cs].chstat)); |
271 | return -1; | 271 | return -1; |
272 | } | 272 | } |
273 | } | 273 | } |
274 | /* Write the data */ | 274 | /* Write the data */ |
275 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; | 275 | unsigned int *tx = &priv->regs->channel[priv->cs].tx; |
276 | if (priv->wordlen > 16) | 276 | if (priv->wordlen > 16) |
277 | writel(((u32 *)txp)[i], tx); | 277 | writel(((u32 *)txp)[i], tx); |
278 | else if (priv->wordlen > 8) | 278 | else if (priv->wordlen > 8) |
279 | writel(((u16 *)txp)[i], tx); | 279 | writel(((u16 *)txp)[i], tx); |
280 | else | 280 | else |
281 | writel(((u8 *)txp)[i], tx); | 281 | writel(((u8 *)txp)[i], tx); |
282 | 282 | ||
283 | /*Read: wait for RX containing data (RXS == 1)*/ | 283 | /*Read: wait for RX containing data (RXS == 1)*/ |
284 | start = get_timer(0); | 284 | start = get_timer(0); |
285 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & | 285 | while (!(readl(&priv->regs->channel[priv->cs].chstat) & |
286 | OMAP3_MCSPI_CHSTAT_RXS)) { | 286 | OMAP3_MCSPI_CHSTAT_RXS)) { |
287 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { | 287 | if (get_timer(start) > SPI_WAIT_TIMEOUT) { |
288 | printf("SPI RXS timed out, status=0x%08x\n", | 288 | printf("SPI RXS timed out, status=0x%08x\n", |
289 | readl(&priv->regs->channel[priv->cs].chstat)); | 289 | readl(&priv->regs->channel[priv->cs].chstat)); |
290 | return -1; | 290 | return -1; |
291 | } | 291 | } |
292 | } | 292 | } |
293 | /* Read the data */ | 293 | /* Read the data */ |
294 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; | 294 | unsigned int *rx = &priv->regs->channel[priv->cs].rx; |
295 | if (priv->wordlen > 16) | 295 | if (priv->wordlen > 16) |
296 | ((u32 *)rxp)[i] = readl(rx); | 296 | ((u32 *)rxp)[i] = readl(rx); |
297 | else if (priv->wordlen > 8) | 297 | else if (priv->wordlen > 8) |
298 | ((u16 *)rxp)[i] = (u16)readl(rx); | 298 | ((u16 *)rxp)[i] = (u16)readl(rx); |
299 | else | 299 | else |
300 | ((u8 *)rxp)[i] = (u8)readl(rx); | 300 | ((u8 *)rxp)[i] = (u8)readl(rx); |
301 | } | 301 | } |
302 | /* Disable the channel */ | 302 | /* Disable the channel */ |
303 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | 303 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
304 | 304 | ||
305 | /*if transfer must be terminated disable the channel*/ | 305 | /*if transfer must be terminated disable the channel*/ |
306 | if (flags & SPI_XFER_END) { | 306 | if (flags & SPI_XFER_END) { |
307 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | 307 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; |
308 | omap3_spi_write_chconf(priv, chconf); | 308 | omap3_spi_write_chconf(priv, chconf); |
309 | } | 309 | } |
310 | 310 | ||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen, | 314 | static int _spi_xfer(struct omap3_spi_priv *priv, unsigned int bitlen, |
315 | const void *dout, void *din, unsigned long flags) | 315 | const void *dout, void *din, unsigned long flags) |
316 | { | 316 | { |
317 | unsigned int len; | 317 | unsigned int len; |
318 | int ret = -1; | 318 | int ret = -1; |
319 | 319 | ||
320 | if (priv->wordlen < 4 || priv->wordlen > 32) { | 320 | if (priv->wordlen < 4 || priv->wordlen > 32) { |
321 | printf("omap3_spi: invalid wordlen %d\n", priv->wordlen); | 321 | printf("omap3_spi: invalid wordlen %d\n", priv->wordlen); |
322 | return -1; | 322 | return -1; |
323 | } | 323 | } |
324 | 324 | ||
325 | if (bitlen % priv->wordlen) | 325 | if (bitlen % priv->wordlen) |
326 | return -1; | 326 | return -1; |
327 | 327 | ||
328 | len = bitlen / priv->wordlen; | 328 | len = bitlen / priv->wordlen; |
329 | 329 | ||
330 | if (bitlen == 0) { /* only change CS */ | 330 | if (bitlen == 0) { /* only change CS */ |
331 | int chconf = readl(&priv->regs->channel[priv->cs].chconf); | 331 | int chconf = readl(&priv->regs->channel[priv->cs].chconf); |
332 | 332 | ||
333 | if (flags & SPI_XFER_BEGIN) { | 333 | if (flags & SPI_XFER_BEGIN) { |
334 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); | 334 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_EN); |
335 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; | 335 | chconf |= OMAP3_MCSPI_CHCONF_FORCE; |
336 | omap3_spi_write_chconf(priv, chconf); | 336 | omap3_spi_write_chconf(priv, chconf); |
337 | } | 337 | } |
338 | if (flags & SPI_XFER_END) { | 338 | if (flags & SPI_XFER_END) { |
339 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; | 339 | chconf &= ~OMAP3_MCSPI_CHCONF_FORCE; |
340 | omap3_spi_write_chconf(priv, chconf); | 340 | omap3_spi_write_chconf(priv, chconf); |
341 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); | 341 | omap3_spi_set_enable(priv, OMAP3_MCSPI_CHCTRL_DIS); |
342 | } | 342 | } |
343 | ret = 0; | 343 | ret = 0; |
344 | } else { | 344 | } else { |
345 | if (dout != NULL && din != NULL) | 345 | if (dout != NULL && din != NULL) |
346 | ret = omap3_spi_txrx(priv, len, dout, din, flags); | 346 | ret = omap3_spi_txrx(priv, len, dout, din, flags); |
347 | else if (dout != NULL) | 347 | else if (dout != NULL) |
348 | ret = omap3_spi_write(priv, len, dout, flags); | 348 | ret = omap3_spi_write(priv, len, dout, flags); |
349 | else if (din != NULL) | 349 | else if (din != NULL) |
350 | ret = omap3_spi_read(priv, len, din, flags); | 350 | ret = omap3_spi_read(priv, len, din, flags); |
351 | } | 351 | } |
352 | return ret; | 352 | return ret; |
353 | } | 353 | } |
354 | 354 | ||
355 | static void _omap3_spi_set_speed(struct omap3_spi_priv *priv) | 355 | static void _omap3_spi_set_speed(struct omap3_spi_priv *priv) |
356 | { | 356 | { |
357 | uint32_t confr, div = 0; | 357 | uint32_t confr, div = 0; |
358 | 358 | ||
359 | confr = readl(&priv->regs->channel[priv->cs].chconf); | 359 | confr = readl(&priv->regs->channel[priv->cs].chconf); |
360 | 360 | ||
361 | /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ | 361 | /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */ |
362 | if (priv->freq) { | 362 | if (priv->freq) { |
363 | while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) | 363 | while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div)) |
364 | > priv->freq) | 364 | > priv->freq) |
365 | div++; | 365 | div++; |
366 | } else { | 366 | } else { |
367 | div = 0xC; | 367 | div = 0xC; |
368 | } | 368 | } |
369 | 369 | ||
370 | /* set clock divisor */ | 370 | /* set clock divisor */ |
371 | confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; | 371 | confr &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK; |
372 | confr |= div << 2; | 372 | confr |= div << 2; |
373 | 373 | ||
374 | omap3_spi_write_chconf(priv, confr); | 374 | omap3_spi_write_chconf(priv, confr); |
375 | } | 375 | } |
376 | 376 | ||
377 | static void _omap3_spi_set_mode(struct omap3_spi_priv *priv) | 377 | static void _omap3_spi_set_mode(struct omap3_spi_priv *priv) |
378 | { | 378 | { |
379 | uint32_t confr; | 379 | uint32_t confr; |
380 | 380 | ||
381 | confr = readl(&priv->regs->channel[priv->cs].chconf); | 381 | confr = readl(&priv->regs->channel[priv->cs].chconf); |
382 | 382 | ||
383 | /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS | 383 | /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS |
384 | * REVISIT: this controller could support SPI_3WIRE mode. | 384 | * REVISIT: this controller could support SPI_3WIRE mode. |
385 | */ | 385 | */ |
386 | if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { | 386 | if (priv->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { |
387 | confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); | 387 | confr &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1); |
388 | confr |= OMAP3_MCSPI_CHCONF_DPE0; | 388 | confr |= OMAP3_MCSPI_CHCONF_DPE0; |
389 | } else { | 389 | } else { |
390 | confr &= ~OMAP3_MCSPI_CHCONF_DPE0; | 390 | confr &= ~OMAP3_MCSPI_CHCONF_DPE0; |
391 | confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1; | 391 | confr |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1; |
392 | } | 392 | } |
393 | 393 | ||
394 | /* set SPI mode 0..3 */ | 394 | /* set SPI mode 0..3 */ |
395 | confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA); | 395 | confr &= ~(OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA); |
396 | if (priv->mode & SPI_CPHA) | 396 | if (priv->mode & SPI_CPHA) |
397 | confr |= OMAP3_MCSPI_CHCONF_PHA; | 397 | confr |= OMAP3_MCSPI_CHCONF_PHA; |
398 | if (priv->mode & SPI_CPOL) | 398 | if (priv->mode & SPI_CPOL) |
399 | confr |= OMAP3_MCSPI_CHCONF_POL; | 399 | confr |= OMAP3_MCSPI_CHCONF_POL; |
400 | 400 | ||
401 | /* set chipselect polarity; manage with FORCE */ | 401 | /* set chipselect polarity; manage with FORCE */ |
402 | if (!(priv->mode & SPI_CS_HIGH)) | 402 | if (!(priv->mode & SPI_CS_HIGH)) |
403 | confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ | 403 | confr |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */ |
404 | else | 404 | else |
405 | confr &= ~OMAP3_MCSPI_CHCONF_EPOL; | 405 | confr &= ~OMAP3_MCSPI_CHCONF_EPOL; |
406 | 406 | ||
407 | /* Transmit & receive mode */ | 407 | /* Transmit & receive mode */ |
408 | confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; | 408 | confr &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; |
409 | 409 | ||
410 | omap3_spi_write_chconf(priv, confr); | 410 | omap3_spi_write_chconf(priv, confr); |
411 | } | 411 | } |
412 | 412 | ||
413 | static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) | 413 | static void _omap3_spi_set_wordlen(struct omap3_spi_priv *priv) |
414 | { | 414 | { |
415 | unsigned int confr; | 415 | unsigned int confr; |
416 | 416 | ||
417 | /* McSPI individual channel configuration */ | 417 | /* McSPI individual channel configuration */ |
418 | confr = readl(&priv->regs->channel[priv->wordlen].chconf); | 418 | confr = readl(&priv->regs->channel[priv->wordlen].chconf); |
419 | 419 | ||
420 | /* wordlength */ | 420 | /* wordlength */ |
421 | confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK; | 421 | confr &= ~OMAP3_MCSPI_CHCONF_WL_MASK; |
422 | confr |= (priv->wordlen - 1) << 7; | 422 | confr |= (priv->wordlen - 1) << 7; |
423 | 423 | ||
424 | omap3_spi_write_chconf(priv, confr); | 424 | omap3_spi_write_chconf(priv, confr); |
425 | } | 425 | } |
426 | 426 | ||
427 | static void spi_reset(struct mcspi *regs) | 427 | static void spi_reset(struct mcspi *regs) |
428 | { | 428 | { |
429 | unsigned int tmp; | 429 | unsigned int tmp; |
430 | 430 | ||
431 | writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, ®s->sysconfig); | 431 | writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, ®s->sysconfig); |
432 | do { | 432 | do { |
433 | tmp = readl(®s->sysstatus); | 433 | tmp = readl(®s->sysstatus); |
434 | } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); | 434 | } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE)); |
435 | 435 | ||
436 | writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | | 436 | writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE | |
437 | OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | | 437 | OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP | |
438 | OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, ®s->sysconfig); | 438 | OMAP3_MCSPI_SYSCONFIG_SMARTIDLE, ®s->sysconfig); |
439 | 439 | ||
440 | writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, ®s->wakeupenable); | 440 | writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, ®s->wakeupenable); |
441 | } | 441 | } |
442 | 442 | ||
443 | static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv) | 443 | static void _omap3_spi_claim_bus(struct omap3_spi_priv *priv) |
444 | { | 444 | { |
445 | unsigned int conf; | 445 | unsigned int conf; |
446 | |||
447 | spi_reset(priv->regs); | ||
448 | |||
449 | /* | 446 | /* |
450 | * setup when switching from (reset default) slave mode | 447 | * setup when switching from (reset default) slave mode |
451 | * to single-channel master mode | 448 | * to single-channel master mode |
452 | */ | 449 | */ |
453 | conf = readl(&priv->regs->modulctrl); | 450 | conf = readl(&priv->regs->modulctrl); |
454 | conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); | 451 | conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS); |
455 | conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; | 452 | conf |= OMAP3_MCSPI_MODULCTRL_SINGLE; |
456 | 453 | ||
457 | writel(conf, &priv->regs->modulctrl); | 454 | writel(conf, &priv->regs->modulctrl); |
458 | } | 455 | } |
459 | 456 | ||
460 | #ifndef CONFIG_DM_SPI | 457 | #ifndef CONFIG_DM_SPI |
461 | 458 | ||
462 | static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave) | 459 | static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave) |
463 | { | 460 | { |
464 | return container_of(slave, struct omap3_spi_priv, slave); | 461 | return container_of(slave, struct omap3_spi_priv, slave); |
465 | } | 462 | } |
466 | 463 | ||
467 | void spi_init(void) | 464 | void spi_init(void) |
468 | { | 465 | { |
469 | /* do nothing */ | 466 | /* do nothing */ |
470 | } | 467 | } |
471 | 468 | ||
472 | void spi_free_slave(struct spi_slave *slave) | 469 | void spi_free_slave(struct spi_slave *slave) |
473 | { | 470 | { |
474 | struct omap3_spi_priv *priv = to_omap3_spi(slave); | 471 | struct omap3_spi_priv *priv = to_omap3_spi(slave); |
475 | 472 | ||
476 | free(priv); | 473 | free(priv); |
477 | } | 474 | } |
478 | 475 | ||
479 | int spi_claim_bus(struct spi_slave *slave) | 476 | int spi_claim_bus(struct spi_slave *slave) |
480 | { | 477 | { |
481 | struct omap3_spi_priv *priv = to_omap3_spi(slave); | 478 | struct omap3_spi_priv *priv = to_omap3_spi(slave); |
482 | 479 | ||
480 | spi_reset(priv->regs); | ||
481 | |||
483 | _omap3_spi_claim_bus(priv); | 482 | _omap3_spi_claim_bus(priv); |
484 | _omap3_spi_set_wordlen(priv); | 483 | _omap3_spi_set_wordlen(priv); |
485 | _omap3_spi_set_mode(priv); | 484 | _omap3_spi_set_mode(priv); |
486 | _omap3_spi_set_speed(priv); | 485 | _omap3_spi_set_speed(priv); |
487 | 486 | ||
488 | return 0; | 487 | return 0; |
489 | } | 488 | } |
490 | 489 | ||
491 | void spi_release_bus(struct spi_slave *slave) | 490 | void spi_release_bus(struct spi_slave *slave) |
492 | { | 491 | { |
493 | struct omap3_spi_priv *priv = to_omap3_spi(slave); | 492 | struct omap3_spi_priv *priv = to_omap3_spi(slave); |
494 | 493 | ||
495 | /* Reset the SPI hardware */ | 494 | writel(OMAP3_MCSPI_MODULCTRL_MS, &priv->regs->modulctrl); |
496 | spi_reset(priv->regs); | ||
497 | } | 495 | } |
498 | 496 | ||
499 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, | 497 | struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, |
500 | unsigned int max_hz, unsigned int mode) | 498 | unsigned int max_hz, unsigned int mode) |
501 | { | 499 | { |
502 | struct omap3_spi_priv *priv; | 500 | struct omap3_spi_priv *priv; |
503 | struct mcspi *regs; | 501 | struct mcspi *regs; |
504 | 502 | ||
505 | /* | 503 | /* |
506 | * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules) | 504 | * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules) |
507 | * with different number of chip selects (CS, channels): | 505 | * with different number of chip selects (CS, channels): |
508 | * McSPI1 has 4 CS (bus 0, cs 0 - 3) | 506 | * McSPI1 has 4 CS (bus 0, cs 0 - 3) |
509 | * McSPI2 has 2 CS (bus 1, cs 0 - 1) | 507 | * McSPI2 has 2 CS (bus 1, cs 0 - 1) |
510 | * McSPI3 has 2 CS (bus 2, cs 0 - 1) | 508 | * McSPI3 has 2 CS (bus 2, cs 0 - 1) |
511 | * McSPI4 has 1 CS (bus 3, cs 0) | 509 | * McSPI4 has 1 CS (bus 3, cs 0) |
512 | */ | 510 | */ |
513 | 511 | ||
514 | switch (bus) { | 512 | switch (bus) { |
515 | case 0: | 513 | case 0: |
516 | regs = (struct mcspi *)OMAP3_MCSPI1_BASE; | 514 | regs = (struct mcspi *)OMAP3_MCSPI1_BASE; |
517 | break; | 515 | break; |
518 | #ifdef OMAP3_MCSPI2_BASE | 516 | #ifdef OMAP3_MCSPI2_BASE |
519 | case 1: | 517 | case 1: |
520 | regs = (struct mcspi *)OMAP3_MCSPI2_BASE; | 518 | regs = (struct mcspi *)OMAP3_MCSPI2_BASE; |
521 | break; | 519 | break; |
522 | #endif | 520 | #endif |
523 | #ifdef OMAP3_MCSPI3_BASE | 521 | #ifdef OMAP3_MCSPI3_BASE |
524 | case 2: | 522 | case 2: |
525 | regs = (struct mcspi *)OMAP3_MCSPI3_BASE; | 523 | regs = (struct mcspi *)OMAP3_MCSPI3_BASE; |
526 | break; | 524 | break; |
527 | #endif | 525 | #endif |
528 | #ifdef OMAP3_MCSPI4_BASE | 526 | #ifdef OMAP3_MCSPI4_BASE |
529 | case 3: | 527 | case 3: |
530 | regs = (struct mcspi *)OMAP3_MCSPI4_BASE; | 528 | regs = (struct mcspi *)OMAP3_MCSPI4_BASE; |
531 | break; | 529 | break; |
532 | #endif | 530 | #endif |
533 | default: | 531 | default: |
534 | printf("SPI error: unsupported bus %i. Supported busses 0 - 3\n", bus); | 532 | printf("SPI error: unsupported bus %i. Supported busses 0 - 3\n", bus); |
535 | return NULL; | 533 | return NULL; |
536 | } | 534 | } |
537 | 535 | ||
538 | if (((bus == 0) && (cs > 3)) || | 536 | if (((bus == 0) && (cs > 3)) || |
539 | ((bus == 1) && (cs > 1)) || | 537 | ((bus == 1) && (cs > 1)) || |
540 | ((bus == 2) && (cs > 1)) || | 538 | ((bus == 2) && (cs > 1)) || |
541 | ((bus == 3) && (cs > 0))) { | 539 | ((bus == 3) && (cs > 0))) { |
542 | printf("SPI error: unsupported chip select %i on bus %i\n", cs, bus); | 540 | printf("SPI error: unsupported chip select %i on bus %i\n", cs, bus); |
543 | return NULL; | 541 | return NULL; |
544 | } | 542 | } |
545 | 543 | ||
546 | if (max_hz > OMAP3_MCSPI_MAX_FREQ) { | 544 | if (max_hz > OMAP3_MCSPI_MAX_FREQ) { |
547 | printf("SPI error: unsupported frequency %i Hz. Max frequency is 48 MHz\n", | 545 | printf("SPI error: unsupported frequency %i Hz. Max frequency is 48 MHz\n", |
548 | max_hz); | 546 | max_hz); |
549 | return NULL; | 547 | return NULL; |
550 | } | 548 | } |
551 | 549 | ||
552 | if (mode > SPI_MODE_3) { | 550 | if (mode > SPI_MODE_3) { |
553 | printf("SPI error: unsupported SPI mode %i\n", mode); | 551 | printf("SPI error: unsupported SPI mode %i\n", mode); |
554 | return NULL; | 552 | return NULL; |
555 | } | 553 | } |
556 | 554 | ||
557 | priv = spi_alloc_slave(struct omap3_spi_priv, bus, cs); | 555 | priv = spi_alloc_slave(struct omap3_spi_priv, bus, cs); |
558 | if (!priv) { | 556 | if (!priv) { |
559 | printf("SPI error: malloc of SPI structure failed\n"); | 557 | printf("SPI error: malloc of SPI structure failed\n"); |
560 | return NULL; | 558 | return NULL; |
561 | } | 559 | } |
562 | 560 | ||
563 | priv->regs = regs; | 561 | priv->regs = regs; |
564 | priv->cs = cs; | 562 | priv->cs = cs; |
565 | priv->freq = max_hz; | 563 | priv->freq = max_hz; |
566 | priv->mode = mode; | 564 | priv->mode = mode; |
567 | priv->wordlen = priv->slave.wordlen; | 565 | priv->wordlen = priv->slave.wordlen; |
568 | #if 0 | 566 | #if 0 |
569 | /* Please migrate to DM_SPI support for this feature. */ | 567 | /* Please migrate to DM_SPI support for this feature. */ |
570 | priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; | 568 | priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; |
571 | #endif | 569 | #endif |
572 | 570 | ||
573 | return &priv->slave; | 571 | return &priv->slave; |
574 | } | 572 | } |
575 | 573 | ||
576 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | 574 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, |
577 | const void *dout, void *din, unsigned long flags) | 575 | const void *dout, void *din, unsigned long flags) |
578 | { | 576 | { |
579 | struct omap3_spi_priv *priv = to_omap3_spi(slave); | 577 | struct omap3_spi_priv *priv = to_omap3_spi(slave); |
580 | 578 | ||
581 | return _spi_xfer(priv, bitlen, dout, din, flags); | 579 | return _spi_xfer(priv, bitlen, dout, din, flags); |
582 | } | 580 | } |
583 | 581 | ||
584 | #else | 582 | #else |
585 | 583 | ||
586 | static int omap3_spi_claim_bus(struct udevice *dev) | 584 | static int omap3_spi_claim_bus(struct udevice *dev) |
587 | { | 585 | { |
588 | struct udevice *bus = dev->parent; | 586 | struct udevice *bus = dev->parent; |
589 | struct omap3_spi_priv *priv = dev_get_priv(bus); | 587 | struct omap3_spi_priv *priv = dev_get_priv(bus); |
590 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | 588 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); |
591 | 589 | ||
592 | priv->cs = slave_plat->cs; | 590 | priv->cs = slave_plat->cs; |
593 | priv->freq = slave_plat->max_hz; | 591 | priv->freq = slave_plat->max_hz; |
594 | 592 | ||
595 | _omap3_spi_claim_bus(priv); | 593 | _omap3_spi_claim_bus(priv); |
596 | 594 | ||
597 | return 0; | 595 | return 0; |
598 | } | 596 | } |
599 | 597 | ||
600 | static int omap3_spi_release_bus(struct udevice *dev) | 598 | static int omap3_spi_release_bus(struct udevice *dev) |
601 | { | 599 | { |
602 | struct udevice *bus = dev->parent; | 600 | struct udevice *bus = dev->parent; |
603 | struct omap3_spi_priv *priv = dev_get_priv(bus); | 601 | struct omap3_spi_priv *priv = dev_get_priv(bus); |
604 | 602 | ||
605 | /* Reset the SPI hardware */ | 603 | writel(OMAP3_MCSPI_MODULCTRL_MS, &priv->regs->modulctrl); |
606 | spi_reset(priv->regs); | ||
607 | 604 | ||
608 | return 0; | 605 | return 0; |
609 | } | 606 | } |
610 | 607 | ||
611 | static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) | 608 | static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) |
612 | { | 609 | { |
613 | struct udevice *bus = dev->parent; | 610 | struct udevice *bus = dev->parent; |
614 | struct omap3_spi_priv *priv = dev_get_priv(bus); | 611 | struct omap3_spi_priv *priv = dev_get_priv(bus); |
615 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | 612 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); |
616 | 613 | ||
617 | priv->cs = slave_plat->cs; | 614 | priv->cs = slave_plat->cs; |
618 | priv->wordlen = wordlen; | 615 | priv->wordlen = wordlen; |
619 | _omap3_spi_set_wordlen(priv); | 616 | _omap3_spi_set_wordlen(priv); |
620 | 617 | ||
621 | return 0; | 618 | return 0; |
622 | } | 619 | } |
623 | 620 | ||
624 | static int omap3_spi_probe(struct udevice *dev) | 621 | static int omap3_spi_probe(struct udevice *dev) |
625 | { | 622 | { |
626 | struct omap3_spi_priv *priv = dev_get_priv(dev); | 623 | struct omap3_spi_priv *priv = dev_get_priv(dev); |
627 | const void *blob = gd->fdt_blob; | 624 | const void *blob = gd->fdt_blob; |
628 | int node = dev_of_offset(dev); | 625 | int node = dev_of_offset(dev); |
629 | 626 | ||
630 | struct omap2_mcspi_platform_config* data = | 627 | struct omap2_mcspi_platform_config* data = |
631 | (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev); | 628 | (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev); |
632 | 629 | ||
633 | priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset); | 630 | priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset); |
634 | if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in")) | 631 | if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in")) |
635 | priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; | 632 | priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; |
636 | else | 633 | else |
637 | priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT; | 634 | priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT; |
638 | priv->wordlen = SPI_DEFAULT_WORDLEN; | 635 | priv->wordlen = SPI_DEFAULT_WORDLEN; |
636 | |||
637 | spi_reset(priv->regs); | ||
638 | |||
639 | return 0; | 639 | return 0; |
640 | } | 640 | } |
641 | 641 | ||
642 | static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen, | 642 | static int omap3_spi_xfer(struct udevice *dev, unsigned int bitlen, |
643 | const void *dout, void *din, unsigned long flags) | 643 | const void *dout, void *din, unsigned long flags) |
644 | { | 644 | { |
645 | struct udevice *bus = dev->parent; | 645 | struct udevice *bus = dev->parent; |
646 | struct omap3_spi_priv *priv = dev_get_priv(bus); | 646 | struct omap3_spi_priv *priv = dev_get_priv(bus); |
647 | 647 | ||
648 | return _spi_xfer(priv, bitlen, dout, din, flags); | 648 | return _spi_xfer(priv, bitlen, dout, din, flags); |
649 | } | 649 | } |
650 | 650 | ||
651 | static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed) | 651 | static int omap3_spi_set_speed(struct udevice *dev, unsigned int speed) |
652 | { | 652 | { |
653 | 653 | ||
654 | struct omap3_spi_priv *priv = dev_get_priv(dev); | 654 | struct omap3_spi_priv *priv = dev_get_priv(dev); |
655 | 655 | ||
656 | priv->freq = speed; | 656 | priv->freq = speed; |
657 | _omap3_spi_set_speed(priv); | 657 | _omap3_spi_set_speed(priv); |
658 | 658 | ||
659 | return 0; | 659 | return 0; |
660 | } | 660 | } |
661 | 661 | ||
662 | static int omap3_spi_set_mode(struct udevice *dev, uint mode) | 662 | static int omap3_spi_set_mode(struct udevice *dev, uint mode) |
663 | { | 663 | { |
664 | struct omap3_spi_priv *priv = dev_get_priv(dev); | 664 | struct omap3_spi_priv *priv = dev_get_priv(dev); |
665 | 665 | ||
666 | priv->mode = mode; | 666 | priv->mode = mode; |
667 | 667 | ||
668 | _omap3_spi_set_mode(priv); | 668 | _omap3_spi_set_mode(priv); |
669 | 669 | ||
670 | return 0; | 670 | return 0; |
671 | } | 671 | } |
672 | 672 | ||
673 | static const struct dm_spi_ops omap3_spi_ops = { | 673 | static const struct dm_spi_ops omap3_spi_ops = { |
674 | .claim_bus = omap3_spi_claim_bus, | 674 | .claim_bus = omap3_spi_claim_bus, |
675 | .release_bus = omap3_spi_release_bus, | 675 | .release_bus = omap3_spi_release_bus, |
676 | .set_wordlen = omap3_spi_set_wordlen, | 676 | .set_wordlen = omap3_spi_set_wordlen, |
677 | .xfer = omap3_spi_xfer, | 677 | .xfer = omap3_spi_xfer, |
678 | .set_speed = omap3_spi_set_speed, | 678 | .set_speed = omap3_spi_set_speed, |
679 | .set_mode = omap3_spi_set_mode, | 679 | .set_mode = omap3_spi_set_mode, |
680 | /* | 680 | /* |
681 | * cs_info is not needed, since we require all chip selects to be | 681 | * cs_info is not needed, since we require all chip selects to be |
682 | * in the device tree explicitly | 682 | * in the device tree explicitly |
683 | */ | 683 | */ |
684 | }; | 684 | }; |
685 | 685 | ||
686 | static struct omap2_mcspi_platform_config omap2_pdata = { | 686 | static struct omap2_mcspi_platform_config omap2_pdata = { |
687 | .regs_offset = 0, | 687 | .regs_offset = 0, |
688 | }; | 688 | }; |
689 | 689 | ||
690 | static struct omap2_mcspi_platform_config omap4_pdata = { | 690 | static struct omap2_mcspi_platform_config omap4_pdata = { |
691 | .regs_offset = OMAP4_MCSPI_REG_OFFSET, | 691 | .regs_offset = OMAP4_MCSPI_REG_OFFSET, |
692 | }; | 692 | }; |
693 | 693 | ||
694 | static const struct udevice_id omap3_spi_ids[] = { | 694 | static const struct udevice_id omap3_spi_ids[] = { |
695 | { .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata }, | 695 | { .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata }, |
696 | { .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata }, | 696 | { .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata }, |
697 | { } | 697 | { } |
698 | }; | 698 | }; |
699 | 699 | ||
700 | U_BOOT_DRIVER(omap3_spi) = { | 700 | U_BOOT_DRIVER(omap3_spi) = { |
701 | .name = "omap3_spi", | 701 | .name = "omap3_spi", |
702 | .id = UCLASS_SPI, | 702 | .id = UCLASS_SPI, |
703 | .of_match = omap3_spi_ids, | 703 | .of_match = omap3_spi_ids, |
704 | .probe = omap3_spi_probe, | 704 | .probe = omap3_spi_probe, |