aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2010-09-09 15:02:48 -0400
committerSascha Hauer <s.hauer@pengutronix.de>2010-10-01 03:32:13 -0400
commit0b599603d8534bc3946a0f07e461c76d7947dfcf (patch)
tree18d5b7a0279f54f2f939b1399aca5f443cbc431f /drivers/spi
parent3b2aa89eb381d2f445aa3c60d8f070a3f55efa63 (diff)
spi/imx: add support for imx51's eCSPI and CSPI
i.MX51 comes with two eCSPI interfaces (that are quite different from what was known before---the tried and tested Freescale way) and a CSPI interface that is identical to the devices found on i.MX25 and i.MX35. This patch is a merge of two very similar patches (by Jason Wang and Sascha Hauer resp.) plus a (now hopefully correct) reimplementation of the clock calculation. Acked-by: Jason Wang <jason77.wang@gmail.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig5
-rw-r--r--drivers/spi/spi_imx.c140
2 files changed, 143 insertions, 2 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 4e9d77bc7d2f..7e631fa51098 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -153,7 +153,10 @@ config SPI_IMX_VER_0_4
153 def_bool y if ARCH_MX31 153 def_bool y if ARCH_MX31
154 154
155config SPI_IMX_VER_0_7 155config SPI_IMX_VER_0_7
156 def_bool y if ARCH_MX25 || ARCH_MX35 156 def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51
157
158config SPI_IMX_VER_2_3
159 def_bool y if ARCH_MX51
157 160
158config SPI_IMX 161config SPI_IMX
159 tristate "Freescale i.MX SPI controllers" 162 tristate "Freescale i.MX SPI controllers"
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 23db9840b9ae..6bab2cfd93c1 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -65,6 +65,7 @@ enum spi_imx_devtype {
65 SPI_IMX_VER_0_4, 65 SPI_IMX_VER_0_4,
66 SPI_IMX_VER_0_5, 66 SPI_IMX_VER_0_5,
67 SPI_IMX_VER_0_7, 67 SPI_IMX_VER_0_7,
68 SPI_IMX_VER_2_3,
68 SPI_IMX_VER_AUTODETECT, 69 SPI_IMX_VER_AUTODETECT,
69}; 70};
70 71
@@ -155,7 +156,7 @@ static unsigned int spi_imx_clkdiv_1(unsigned int fin,
155 return max; 156 return max;
156} 157}
157 158
158/* MX1, MX31, MX35 */ 159/* MX1, MX31, MX35, MX51 CSPI */
159static unsigned int spi_imx_clkdiv_2(unsigned int fin, 160static unsigned int spi_imx_clkdiv_2(unsigned int fin,
160 unsigned int fspi) 161 unsigned int fspi)
161{ 162{
@@ -170,6 +171,128 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
170 return 7; 171 return 7;
171} 172}
172 173
174#define SPI_IMX2_3_CTRL 0x08
175#define SPI_IMX2_3_CTRL_ENABLE (1 << 0)
176#define SPI_IMX2_3_CTRL_XCH (1 << 2)
177#define SPI_IMX2_3_CTRL_MODE(cs) (1 << ((cs) + 4))
178#define SPI_IMX2_3_CTRL_POSTDIV_OFFSET 8
179#define SPI_IMX2_3_CTRL_PREDIV_OFFSET 12
180#define SPI_IMX2_3_CTRL_CS(cs) ((cs) << 18)
181#define SPI_IMX2_3_CTRL_BL_OFFSET 20
182
183#define SPI_IMX2_3_CONFIG 0x0c
184#define SPI_IMX2_3_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
185#define SPI_IMX2_3_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4))
186#define SPI_IMX2_3_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8))
187#define SPI_IMX2_3_CONFIG_SSBPOL(cs) (1 << ((cs) + 12))
188
189#define SPI_IMX2_3_INT 0x10
190#define SPI_IMX2_3_INT_TEEN (1 << 0)
191#define SPI_IMX2_3_INT_RREN (1 << 3)
192
193#define SPI_IMX2_3_STAT 0x18
194#define SPI_IMX2_3_STAT_RR (1 << 3)
195
196/* MX51 eCSPI */
197static unsigned int spi_imx2_3_clkdiv(unsigned int fin, unsigned int fspi)
198{
199 /*
200 * there are two 4-bit dividers, the pre-divider divides by
201 * $pre, the post-divider by 2^$post
202 */
203 unsigned int pre, post;
204
205 if (unlikely(fspi > fin))
206 return 0;
207
208 post = fls(fin) - fls(fspi);
209 if (fin > fspi << post)
210 post++;
211
212 /* now we have: (fin <= fspi << post) with post being minimal */
213
214 post = max(4U, post) - 4;
215 if (unlikely(post > 0xf)) {
216 pr_err("%s: cannot set clock freq: %u (base freq: %u)\n",
217 __func__, fspi, fin);
218 return 0xff;
219 }
220
221 pre = DIV_ROUND_UP(fin, fspi << post) - 1;
222
223 pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
224 __func__, fin, fspi, post, pre);
225 return (pre << SPI_IMX2_3_CTRL_PREDIV_OFFSET) |
226 (post << SPI_IMX2_3_CTRL_POSTDIV_OFFSET);
227}
228
229static void __maybe_unused spi_imx2_3_intctrl(struct spi_imx_data *spi_imx, int enable)
230{
231 unsigned val = 0;
232
233 if (enable & MXC_INT_TE)
234 val |= SPI_IMX2_3_INT_TEEN;
235
236 if (enable & MXC_INT_RR)
237 val |= SPI_IMX2_3_INT_RREN;
238
239 writel(val, spi_imx->base + SPI_IMX2_3_INT);
240}
241
242static void __maybe_unused spi_imx2_3_trigger(struct spi_imx_data *spi_imx)
243{
244 u32 reg;
245
246 reg = readl(spi_imx->base + SPI_IMX2_3_CTRL);
247 reg |= SPI_IMX2_3_CTRL_XCH;
248 writel(reg, spi_imx->base + SPI_IMX2_3_CTRL);
249}
250
251static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx,
252 struct spi_imx_config *config)
253{
254 u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0;
255
256 /* set master mode */
257 ctrl |= SPI_IMX2_3_CTRL_MODE(config->cs);
258
259 /* set clock speed */
260 ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz);
261
262 /* set chip select to use */
263 ctrl |= SPI_IMX2_3_CTRL_CS(config->cs);
264
265 ctrl |= (config->bpw - 1) << SPI_IMX2_3_CTRL_BL_OFFSET;
266
267 cfg |= SPI_IMX2_3_CONFIG_SBBCTRL(config->cs);
268
269 if (config->mode & SPI_CPHA)
270 cfg |= SPI_IMX2_3_CONFIG_SCLKPHA(config->cs);
271
272 if (config->mode & SPI_CPOL)
273 cfg |= SPI_IMX2_3_CONFIG_SCLKPOL(config->cs);
274
275 if (config->mode & SPI_CS_HIGH)
276 cfg |= SPI_IMX2_3_CONFIG_SSBPOL(config->cs);
277
278 writel(ctrl, spi_imx->base + SPI_IMX2_3_CTRL);
279 writel(cfg, spi_imx->base + SPI_IMX2_3_CONFIG);
280
281 return 0;
282}
283
284static int __maybe_unused spi_imx2_3_rx_available(struct spi_imx_data *spi_imx)
285{
286 return readl(spi_imx->base + SPI_IMX2_3_STAT) & SPI_IMX2_3_STAT_RR;
287}
288
289static void __maybe_unused spi_imx2_3_reset(struct spi_imx_data *spi_imx)
290{
291 /* drain receive buffer */
292 while (spi_imx2_3_rx_available(spi_imx))
293 readl(spi_imx->base + MXC_CSPIRXDATA);
294}
295
173#define MX31_INTREG_TEEN (1 << 0) 296#define MX31_INTREG_TEEN (1 << 0)
174#define MX31_INTREG_RREN (1 << 3) 297#define MX31_INTREG_RREN (1 << 3)
175 298
@@ -447,6 +570,15 @@ static struct spi_imx_devtype_data spi_imx_devtype_data[] __devinitdata = {
447 .reset = spi_imx0_4_reset, 570 .reset = spi_imx0_4_reset,
448 }, 571 },
449#endif 572#endif
573#ifdef CONFIG_SPI_IMX_VER_2_3
574 [SPI_IMX_VER_2_3] = {
575 .intctrl = spi_imx2_3_intctrl,
576 .config = spi_imx2_3_config,
577 .trigger = spi_imx2_3_trigger,
578 .rx_available = spi_imx2_3_rx_available,
579 .reset = spi_imx2_3_reset,
580 },
581#endif
450}; 582};
451 583
452static void spi_imx_chipselect(struct spi_device *spi, int is_active) 584static void spi_imx_chipselect(struct spi_device *spi, int is_active)
@@ -603,6 +735,12 @@ static struct platform_device_id spi_imx_devtype[] = {
603 .name = "imx35-cspi", 735 .name = "imx35-cspi",
604 .driver_data = SPI_IMX_VER_0_7, 736 .driver_data = SPI_IMX_VER_0_7,
605 }, { 737 }, {
738 .name = "imx51-cspi",
739 .driver_data = SPI_IMX_VER_0_7,
740 }, {
741 .name = "imx51-ecspi",
742 .driver_data = SPI_IMX_VER_2_3,
743 }, {
606 /* sentinel */ 744 /* sentinel */
607 } 745 }
608}; 746};