]>
Commit | Line | Data |
---|---|---|
35c9049b CM |
1 | /* |
2 | * OMAP7xx SPI 100k controller driver | |
3 | * Author: Fabrice Crohas <[email protected]> | |
4 | * from original omap1_mcspi driver | |
5 | * | |
6 | * Copyright (C) 2005, 2006 Nokia Corporation | |
7 | * Author: Samuel Ortiz <[email protected]> and | |
8 | * Juha Yrj�l� <[email protected]> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
35c9049b CM |
19 | */ |
20 | #include <linux/kernel.h> | |
21 | #include <linux/init.h> | |
22 | #include <linux/interrupt.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/device.h> | |
25 | #include <linux/delay.h> | |
26 | #include <linux/platform_device.h> | |
db91841b | 27 | #include <linux/pm_runtime.h> |
35c9049b CM |
28 | #include <linux/err.h> |
29 | #include <linux/clk.h> | |
30 | #include <linux/io.h> | |
31 | #include <linux/gpio.h> | |
5a0e3ad6 | 32 | #include <linux/slab.h> |
35c9049b CM |
33 | |
34 | #include <linux/spi/spi.h> | |
35 | ||
35c9049b CM |
36 | #define OMAP1_SPI100K_MAX_FREQ 48000000 |
37 | ||
38 | #define ICR_SPITAS (OMAP7XX_ICR_BASE + 0x12) | |
39 | ||
40 | #define SPI_SETUP1 0x00 | |
41 | #define SPI_SETUP2 0x02 | |
42 | #define SPI_CTRL 0x04 | |
43 | #define SPI_STATUS 0x06 | |
44 | #define SPI_TX_LSB 0x08 | |
45 | #define SPI_TX_MSB 0x0a | |
46 | #define SPI_RX_LSB 0x0c | |
47 | #define SPI_RX_MSB 0x0e | |
48 | ||
49 | #define SPI_SETUP1_INT_READ_ENABLE (1UL << 5) | |
50 | #define SPI_SETUP1_INT_WRITE_ENABLE (1UL << 4) | |
51 | #define SPI_SETUP1_CLOCK_DIVISOR(x) ((x) << 1) | |
52 | #define SPI_SETUP1_CLOCK_ENABLE (1UL << 0) | |
53 | ||
54 | #define SPI_SETUP2_ACTIVE_EDGE_FALLING (0UL << 0) | |
55 | #define SPI_SETUP2_ACTIVE_EDGE_RISING (1UL << 0) | |
56 | #define SPI_SETUP2_NEGATIVE_LEVEL (0UL << 5) | |
57 | #define SPI_SETUP2_POSITIVE_LEVEL (1UL << 5) | |
58 | #define SPI_SETUP2_LEVEL_TRIGGER (0UL << 10) | |
59 | #define SPI_SETUP2_EDGE_TRIGGER (1UL << 10) | |
60 | ||
61 | #define SPI_CTRL_SEN(x) ((x) << 7) | |
62 | #define SPI_CTRL_WORD_SIZE(x) (((x) - 1) << 2) | |
63 | #define SPI_CTRL_WR (1UL << 1) | |
64 | #define SPI_CTRL_RD (1UL << 0) | |
65 | ||
66 | #define SPI_STATUS_WE (1UL << 1) | |
67 | #define SPI_STATUS_RD (1UL << 0) | |
68 | ||
35c9049b CM |
69 | /* use PIO for small transfers, avoiding DMA setup/teardown overhead and |
70 | * cache operations; better heuristics consider wordsize and bitrate. | |
71 | */ | |
72 | #define DMA_MIN_BYTES 8 | |
73 | ||
74 | #define SPI_RUNNING 0 | |
75 | #define SPI_SHUTDOWN 1 | |
76 | ||
77 | struct omap1_spi100k { | |
35c9049b CM |
78 | struct clk *ick; |
79 | struct clk *fck; | |
80 | ||
81 | /* Virtual base address of the controller */ | |
82 | void __iomem *base; | |
35c9049b CM |
83 | }; |
84 | ||
85 | struct omap1_spi100k_cs { | |
86 | void __iomem *base; | |
87 | int word_len; | |
88 | }; | |
89 | ||
35c9049b CM |
90 | static void spi100k_enable_clock(struct spi_master *master) |
91 | { | |
92 | unsigned int val; | |
93 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
94 | ||
95 | /* enable SPI */ | |
96 | val = readw(spi100k->base + SPI_SETUP1); | |
97 | val |= SPI_SETUP1_CLOCK_ENABLE; | |
98 | writew(val, spi100k->base + SPI_SETUP1); | |
99 | } | |
100 | ||
101 | static void spi100k_disable_clock(struct spi_master *master) | |
102 | { | |
103 | unsigned int val; | |
104 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
105 | ||
106 | /* disable SPI */ | |
107 | val = readw(spi100k->base + SPI_SETUP1); | |
108 | val &= ~SPI_SETUP1_CLOCK_ENABLE; | |
109 | writew(val, spi100k->base + SPI_SETUP1); | |
110 | } | |
111 | ||
112 | static void spi100k_write_data(struct spi_master *master, int len, int data) | |
113 | { | |
114 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
115 | ||
5c2818cd CM |
116 | /* write 16-bit word, shifting 8-bit data if necessary */ |
117 | if (len <= 8) { | |
118 | data <<= 8; | |
119 | len = 16; | |
120 | } | |
121 | ||
35c9049b | 122 | spi100k_enable_clock(master); |
31804f63 | 123 | writew(data , spi100k->base + SPI_TX_MSB); |
35c9049b CM |
124 | |
125 | writew(SPI_CTRL_SEN(0) | | |
126 | SPI_CTRL_WORD_SIZE(len) | | |
127 | SPI_CTRL_WR, | |
128 | spi100k->base + SPI_CTRL); | |
129 | ||
130 | /* Wait for bit ack send change */ | |
31804f63 JH |
131 | while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE) |
132 | ; | |
35c9049b CM |
133 | udelay(1000); |
134 | ||
135 | spi100k_disable_clock(master); | |
136 | } | |
137 | ||
138 | static int spi100k_read_data(struct spi_master *master, int len) | |
139 | { | |
31804f63 | 140 | int dataH, dataL; |
35c9049b CM |
141 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); |
142 | ||
5c2818cd CM |
143 | /* Always do at least 16 bits */ |
144 | if (len <= 8) | |
145 | len = 16; | |
146 | ||
35c9049b CM |
147 | spi100k_enable_clock(master); |
148 | writew(SPI_CTRL_SEN(0) | | |
149 | SPI_CTRL_WORD_SIZE(len) | | |
150 | SPI_CTRL_RD, | |
151 | spi100k->base + SPI_CTRL); | |
152 | ||
31804f63 JH |
153 | while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD) |
154 | ; | |
35c9049b CM |
155 | udelay(1000); |
156 | ||
157 | dataL = readw(spi100k->base + SPI_RX_LSB); | |
158 | dataH = readw(spi100k->base + SPI_RX_MSB); | |
159 | spi100k_disable_clock(master); | |
160 | ||
161 | return dataL; | |
162 | } | |
163 | ||
164 | static void spi100k_open(struct spi_master *master) | |
165 | { | |
166 | /* get control of SPI */ | |
167 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
168 | ||
169 | writew(SPI_SETUP1_INT_READ_ENABLE | | |
170 | SPI_SETUP1_INT_WRITE_ENABLE | | |
171 | SPI_SETUP1_CLOCK_DIVISOR(0), spi100k->base + SPI_SETUP1); | |
172 | ||
173 | /* configure clock and interrupts */ | |
174 | writew(SPI_SETUP2_ACTIVE_EDGE_FALLING | | |
175 | SPI_SETUP2_NEGATIVE_LEVEL | | |
176 | SPI_SETUP2_LEVEL_TRIGGER, spi100k->base + SPI_SETUP2); | |
177 | } | |
178 | ||
179 | static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable) | |
180 | { | |
181 | if (enable) | |
182 | writew(0x05fc, spi100k->base + SPI_CTRL); | |
183 | else | |
184 | writew(0x05fd, spi100k->base + SPI_CTRL); | |
185 | } | |
186 | ||
187 | static unsigned | |
188 | omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) | |
189 | { | |
35c9049b CM |
190 | struct omap1_spi100k_cs *cs = spi->controller_state; |
191 | unsigned int count, c; | |
192 | int word_len; | |
193 | ||
35c9049b CM |
194 | count = xfer->len; |
195 | c = count; | |
196 | word_len = cs->word_len; | |
197 | ||
35c9049b CM |
198 | if (word_len <= 8) { |
199 | u8 *rx; | |
200 | const u8 *tx; | |
201 | ||
202 | rx = xfer->rx_buf; | |
203 | tx = xfer->tx_buf; | |
204 | do { | |
31804f63 | 205 | c -= 1; |
35c9049b | 206 | if (xfer->tx_buf != NULL) |
5c2818cd | 207 | spi100k_write_data(spi->master, word_len, *tx++); |
35c9049b | 208 | if (xfer->rx_buf != NULL) |
5c2818cd | 209 | *rx++ = spi100k_read_data(spi->master, word_len); |
31804f63 | 210 | } while (c); |
35c9049b CM |
211 | } else if (word_len <= 16) { |
212 | u16 *rx; | |
213 | const u16 *tx; | |
214 | ||
215 | rx = xfer->rx_buf; | |
216 | tx = xfer->tx_buf; | |
217 | do { | |
31804f63 | 218 | c -= 2; |
35c9049b | 219 | if (xfer->tx_buf != NULL) |
31804f63 | 220 | spi100k_write_data(spi->master, word_len, *tx++); |
35c9049b | 221 | if (xfer->rx_buf != NULL) |
31804f63 JH |
222 | *rx++ = spi100k_read_data(spi->master, word_len); |
223 | } while (c); | |
35c9049b CM |
224 | } else if (word_len <= 32) { |
225 | u32 *rx; | |
226 | const u32 *tx; | |
227 | ||
228 | rx = xfer->rx_buf; | |
229 | tx = xfer->tx_buf; | |
230 | do { | |
31804f63 | 231 | c -= 4; |
35c9049b | 232 | if (xfer->tx_buf != NULL) |
31804f63 | 233 | spi100k_write_data(spi->master, word_len, *tx); |
35c9049b | 234 | if (xfer->rx_buf != NULL) |
31804f63 JH |
235 | *rx = spi100k_read_data(spi->master, word_len); |
236 | } while (c); | |
35c9049b CM |
237 | } |
238 | return count - c; | |
239 | } | |
240 | ||
241 | /* called only when no transfer is active to this device */ | |
242 | static int omap1_spi100k_setup_transfer(struct spi_device *spi, | |
243 | struct spi_transfer *t) | |
244 | { | |
245 | struct omap1_spi100k *spi100k = spi_master_get_devdata(spi->master); | |
246 | struct omap1_spi100k_cs *cs = spi->controller_state; | |
76f67ea9 | 247 | u8 word_len; |
35c9049b | 248 | |
76f67ea9 | 249 | if (t != NULL) |
35c9049b | 250 | word_len = t->bits_per_word; |
76f67ea9 JN |
251 | else |
252 | word_len = spi->bits_per_word; | |
35c9049b CM |
253 | |
254 | if (spi->bits_per_word > 32) | |
255 | return -EINVAL; | |
256 | cs->word_len = word_len; | |
257 | ||
258 | /* SPI init before transfer */ | |
259 | writew(0x3e , spi100k->base + SPI_SETUP1); | |
260 | writew(0x00 , spi100k->base + SPI_STATUS); | |
261 | writew(0x3e , spi100k->base + SPI_CTRL); | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
266 | /* the spi->mode bits understood by this driver: */ | |
267 | #define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH) | |
268 | ||
269 | static int omap1_spi100k_setup(struct spi_device *spi) | |
270 | { | |
271 | int ret; | |
272 | struct omap1_spi100k *spi100k; | |
273 | struct omap1_spi100k_cs *cs = spi->controller_state; | |
274 | ||
35c9049b CM |
275 | spi100k = spi_master_get_devdata(spi->master); |
276 | ||
277 | if (!cs) { | |
d1c18caa | 278 | cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); |
35c9049b CM |
279 | if (!cs) |
280 | return -ENOMEM; | |
281 | cs->base = spi100k->base + spi->chip_select * 0x14; | |
282 | spi->controller_state = cs; | |
283 | } | |
284 | ||
285 | spi100k_open(spi->master); | |
286 | ||
13cd19e8 MB |
287 | clk_prepare_enable(spi100k->ick); |
288 | clk_prepare_enable(spi100k->fck); | |
35c9049b CM |
289 | |
290 | ret = omap1_spi100k_setup_transfer(spi, NULL); | |
291 | ||
13cd19e8 MB |
292 | clk_disable_unprepare(spi100k->ick); |
293 | clk_disable_unprepare(spi100k->fck); | |
35c9049b CM |
294 | |
295 | return ret; | |
296 | } | |
297 | ||
e8153ab3 MB |
298 | static int omap1_spi100k_transfer_one_message(struct spi_master *master, |
299 | struct spi_message *m) | |
300 | { | |
301 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
302 | struct spi_device *spi = m->spi; | |
303 | struct spi_transfer *t = NULL; | |
304 | int cs_active = 0; | |
e8153ab3 MB |
305 | int status = 0; |
306 | ||
307 | list_for_each_entry(t, &m->transfers, transfer_list) { | |
308 | if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { | |
309 | status = -EINVAL; | |
310 | break; | |
311 | } | |
76f67ea9 JN |
312 | status = omap1_spi100k_setup_transfer(spi, t); |
313 | if (status < 0) | |
314 | break; | |
e8153ab3 MB |
315 | |
316 | if (!cs_active) { | |
317 | omap1_spi100k_force_cs(spi100k, 1); | |
318 | cs_active = 1; | |
319 | } | |
320 | ||
321 | if (t->len) { | |
322 | unsigned count; | |
323 | ||
324 | count = omap1_spi100k_txrx_pio(spi, t); | |
325 | m->actual_length += count; | |
326 | ||
327 | if (count != t->len) { | |
328 | status = -EIO; | |
329 | break; | |
330 | } | |
331 | } | |
332 | ||
333 | if (t->delay_usecs) | |
334 | udelay(t->delay_usecs); | |
335 | ||
336 | /* ignore the "leave it on after last xfer" hint */ | |
337 | ||
338 | if (t->cs_change) { | |
339 | omap1_spi100k_force_cs(spi100k, 0); | |
340 | cs_active = 0; | |
341 | } | |
342 | } | |
343 | ||
76f67ea9 | 344 | status = omap1_spi100k_setup_transfer(spi, NULL); |
e8153ab3 MB |
345 | |
346 | if (cs_active) | |
347 | omap1_spi100k_force_cs(spi100k, 0); | |
348 | ||
349 | m->status = status; | |
da60b855 MB |
350 | |
351 | spi_finalize_current_message(master); | |
e8153ab3 MB |
352 | |
353 | return status; | |
354 | } | |
355 | ||
fd4a319b | 356 | static int omap1_spi100k_probe(struct platform_device *pdev) |
35c9049b CM |
357 | { |
358 | struct spi_master *master; | |
359 | struct omap1_spi100k *spi100k; | |
360 | int status = 0; | |
361 | ||
362 | if (!pdev->id) | |
363 | return -EINVAL; | |
364 | ||
31804f63 | 365 | master = spi_alloc_master(&pdev->dev, sizeof(*spi100k)); |
35c9049b CM |
366 | if (master == NULL) { |
367 | dev_dbg(&pdev->dev, "master allocation failed\n"); | |
368 | return -ENOMEM; | |
369 | } | |
370 | ||
371 | if (pdev->id != -1) | |
31804f63 | 372 | master->bus_num = pdev->id; |
35c9049b CM |
373 | |
374 | master->setup = omap1_spi100k_setup; | |
da60b855 | 375 | master->transfer_one_message = omap1_spi100k_transfer_one_message; |
35c9049b CM |
376 | master->num_chipselect = 2; |
377 | master->mode_bits = MODEBITS; | |
24778be2 | 378 | master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); |
69ea672a MB |
379 | master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16); |
380 | master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ; | |
db91841b | 381 | master->auto_runtime_pm = true; |
35c9049b | 382 | |
35c9049b | 383 | spi100k = spi_master_get_devdata(master); |
35c9049b CM |
384 | |
385 | /* | |
386 | * The memory region base address is taken as the platform_data. | |
387 | * You should allocate this with ioremap() before initializing | |
388 | * the SPI. | |
389 | */ | |
8074cf06 | 390 | spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev); |
35c9049b | 391 | |
022a9412 | 392 | spi100k->ick = devm_clk_get(&pdev->dev, "ick"); |
35c9049b CM |
393 | if (IS_ERR(spi100k->ick)) { |
394 | dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); | |
395 | status = PTR_ERR(spi100k->ick); | |
022a9412 | 396 | goto err; |
35c9049b CM |
397 | } |
398 | ||
022a9412 | 399 | spi100k->fck = devm_clk_get(&pdev->dev, "fck"); |
35c9049b CM |
400 | if (IS_ERR(spi100k->fck)) { |
401 | dev_dbg(&pdev->dev, "can't get spi100k_fck\n"); | |
402 | status = PTR_ERR(spi100k->fck); | |
022a9412 | 403 | goto err; |
35c9049b CM |
404 | } |
405 | ||
db91841b MB |
406 | status = clk_prepare_enable(spi100k->ick); |
407 | if (status != 0) { | |
408 | dev_err(&pdev->dev, "failed to enable ick: %d\n", status); | |
409 | goto err; | |
410 | } | |
411 | ||
412 | status = clk_prepare_enable(spi100k->fck); | |
413 | if (status != 0) { | |
414 | dev_err(&pdev->dev, "failed to enable fck: %d\n", status); | |
415 | goto err_ick; | |
416 | } | |
417 | ||
418 | pm_runtime_enable(&pdev->dev); | |
419 | pm_runtime_set_active(&pdev->dev); | |
420 | ||
5c4c5c7b | 421 | status = devm_spi_register_master(&pdev->dev, master); |
35c9049b | 422 | if (status < 0) |
db91841b | 423 | goto err_fck; |
35c9049b | 424 | |
35c9049b CM |
425 | return status; |
426 | ||
db91841b MB |
427 | err_fck: |
428 | clk_disable_unprepare(spi100k->fck); | |
429 | err_ick: | |
430 | clk_disable_unprepare(spi100k->ick); | |
022a9412 | 431 | err: |
35c9049b CM |
432 | spi_master_put(master); |
433 | return status; | |
434 | } | |
435 | ||
db91841b MB |
436 | static int omap1_spi100k_remove(struct platform_device *pdev) |
437 | { | |
438 | struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); | |
439 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
440 | ||
441 | pm_runtime_disable(&pdev->dev); | |
442 | ||
443 | clk_disable_unprepare(spi100k->fck); | |
444 | clk_disable_unprepare(spi100k->ick); | |
445 | ||
446 | return 0; | |
447 | } | |
448 | ||
449 | #ifdef CONFIG_PM | |
450 | static int omap1_spi100k_runtime_suspend(struct device *dev) | |
451 | { | |
452 | struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); | |
453 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
454 | ||
455 | clk_disable_unprepare(spi100k->ick); | |
456 | clk_disable_unprepare(spi100k->fck); | |
457 | ||
458 | return 0; | |
459 | } | |
460 | ||
461 | static int omap1_spi100k_runtime_resume(struct device *dev) | |
462 | { | |
463 | struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); | |
464 | struct omap1_spi100k *spi100k = spi_master_get_devdata(master); | |
465 | int ret; | |
466 | ||
467 | ret = clk_prepare_enable(spi100k->ick); | |
468 | if (ret != 0) { | |
469 | dev_err(dev, "Failed to enable ick: %d\n", ret); | |
470 | return ret; | |
471 | } | |
472 | ||
473 | ret = clk_prepare_enable(spi100k->fck); | |
474 | if (ret != 0) { | |
475 | dev_err(dev, "Failed to enable fck: %d\n", ret); | |
476 | clk_disable_unprepare(spi100k->ick); | |
477 | return ret; | |
478 | } | |
479 | ||
480 | return 0; | |
481 | } | |
482 | #endif | |
483 | ||
484 | static const struct dev_pm_ops omap1_spi100k_pm = { | |
485 | SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend, | |
486 | omap1_spi100k_runtime_resume, NULL) | |
487 | }; | |
488 | ||
35c9049b CM |
489 | static struct platform_driver omap1_spi100k_driver = { |
490 | .driver = { | |
491 | .name = "omap1_spi100k", | |
db91841b | 492 | .pm = &omap1_spi100k_pm, |
35c9049b | 493 | }, |
2d0c6148 | 494 | .probe = omap1_spi100k_probe, |
db91841b | 495 | .remove = omap1_spi100k_remove, |
35c9049b CM |
496 | }; |
497 | ||
2d0c6148 | 498 | module_platform_driver(omap1_spi100k_driver); |
35c9049b CM |
499 | |
500 | MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver"); | |
501 | MODULE_AUTHOR("Fabrice Crohas <[email protected]>"); | |
502 | MODULE_LICENSE("GPL"); |