.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Driver for Broadcom BCM2835 auxiliary SPI Controllers |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Based on: spi-bcm2835.c |
---|
8 | 9 | * |
---|
9 | 10 | * Copyright (C) 2015 Martin Sperl |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or modify |
---|
12 | | - * it under the terms of the GNU General Public License as published by |
---|
13 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
14 | | - * (at your option) any later version. |
---|
15 | | - * |
---|
16 | | - * This program is distributed in the hope that it will be useful, |
---|
17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
19 | | - * GNU General Public License for more details. |
---|
20 | 11 | */ |
---|
21 | 12 | |
---|
22 | 13 | #include <linux/clk.h> |
---|
23 | 14 | #include <linux/completion.h> |
---|
| 15 | +#include <linux/debugfs.h> |
---|
24 | 16 | #include <linux/delay.h> |
---|
25 | 17 | #include <linux/err.h> |
---|
26 | 18 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
35 | 27 | #include <linux/regmap.h> |
---|
36 | 28 | #include <linux/spi/spi.h> |
---|
37 | 29 | #include <linux/spinlock.h> |
---|
| 30 | + |
---|
| 31 | +/* define polling limits */ |
---|
| 32 | +static unsigned int polling_limit_us = 30; |
---|
| 33 | +module_param(polling_limit_us, uint, 0664); |
---|
| 34 | +MODULE_PARM_DESC(polling_limit_us, |
---|
| 35 | + "time in us to run a transfer in polling mode - if zero no polling is used\n"); |
---|
38 | 36 | |
---|
39 | 37 | /* |
---|
40 | 38 | * spi register defines |
---|
.. | .. |
---|
88 | 86 | #define BCM2835_AUX_SPI_STAT_BUSY 0x00000040 |
---|
89 | 87 | #define BCM2835_AUX_SPI_STAT_BITCOUNT 0x0000003F |
---|
90 | 88 | |
---|
91 | | -/* timeout values */ |
---|
92 | | -#define BCM2835_AUX_SPI_POLLING_LIMIT_US 30 |
---|
93 | | -#define BCM2835_AUX_SPI_POLLING_JIFFIES 2 |
---|
94 | | - |
---|
95 | 89 | struct bcm2835aux_spi { |
---|
96 | 90 | void __iomem *regs; |
---|
97 | 91 | struct clk *clk; |
---|
.. | .. |
---|
102 | 96 | int tx_len; |
---|
103 | 97 | int rx_len; |
---|
104 | 98 | int pending; |
---|
| 99 | + |
---|
| 100 | + u64 count_transfer_polling; |
---|
| 101 | + u64 count_transfer_irq; |
---|
| 102 | + u64 count_transfer_irq_after_poll; |
---|
| 103 | + |
---|
| 104 | + struct dentry *debugfs_dir; |
---|
105 | 105 | }; |
---|
| 106 | + |
---|
| 107 | +#if defined(CONFIG_DEBUG_FS) |
---|
| 108 | +static void bcm2835aux_debugfs_create(struct bcm2835aux_spi *bs, |
---|
| 109 | + const char *dname) |
---|
| 110 | +{ |
---|
| 111 | + char name[64]; |
---|
| 112 | + struct dentry *dir; |
---|
| 113 | + |
---|
| 114 | + /* get full name */ |
---|
| 115 | + snprintf(name, sizeof(name), "spi-bcm2835aux-%s", dname); |
---|
| 116 | + |
---|
| 117 | + /* the base directory */ |
---|
| 118 | + dir = debugfs_create_dir(name, NULL); |
---|
| 119 | + bs->debugfs_dir = dir; |
---|
| 120 | + |
---|
| 121 | + /* the counters */ |
---|
| 122 | + debugfs_create_u64("count_transfer_polling", 0444, dir, |
---|
| 123 | + &bs->count_transfer_polling); |
---|
| 124 | + debugfs_create_u64("count_transfer_irq", 0444, dir, |
---|
| 125 | + &bs->count_transfer_irq); |
---|
| 126 | + debugfs_create_u64("count_transfer_irq_after_poll", 0444, dir, |
---|
| 127 | + &bs->count_transfer_irq_after_poll); |
---|
| 128 | +} |
---|
| 129 | + |
---|
| 130 | +static void bcm2835aux_debugfs_remove(struct bcm2835aux_spi *bs) |
---|
| 131 | +{ |
---|
| 132 | + debugfs_remove_recursive(bs->debugfs_dir); |
---|
| 133 | + bs->debugfs_dir = NULL; |
---|
| 134 | +} |
---|
| 135 | +#else |
---|
| 136 | +static void bcm2835aux_debugfs_create(struct bcm2835aux_spi *bs, |
---|
| 137 | + const char *dname) |
---|
| 138 | +{ |
---|
| 139 | +} |
---|
| 140 | + |
---|
| 141 | +static void bcm2835aux_debugfs_remove(struct bcm2835aux_spi *bs) |
---|
| 142 | +{ |
---|
| 143 | +} |
---|
| 144 | +#endif /* CONFIG_DEBUG_FS */ |
---|
106 | 145 | |
---|
107 | 146 | static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) |
---|
108 | 147 | { |
---|
.. | .. |
---|
123 | 162 | data = bcm2835aux_rd(bs, BCM2835_AUX_SPI_IO); |
---|
124 | 163 | if (bs->rx_buf) { |
---|
125 | 164 | switch (count) { |
---|
126 | | - case 4: |
---|
127 | | - *bs->rx_buf++ = (data >> 24) & 0xff; |
---|
128 | | - /* fallthrough */ |
---|
129 | 165 | case 3: |
---|
130 | 166 | *bs->rx_buf++ = (data >> 16) & 0xff; |
---|
131 | | - /* fallthrough */ |
---|
| 167 | + fallthrough; |
---|
132 | 168 | case 2: |
---|
133 | 169 | *bs->rx_buf++ = (data >> 8) & 0xff; |
---|
134 | | - /* fallthrough */ |
---|
| 170 | + fallthrough; |
---|
135 | 171 | case 1: |
---|
136 | 172 | *bs->rx_buf++ = (data >> 0) & 0xff; |
---|
137 | 173 | /* fallthrough - no default */ |
---|
.. | .. |
---|
245 | 281 | { |
---|
246 | 282 | struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
---|
247 | 283 | |
---|
| 284 | + /* update statistics */ |
---|
| 285 | + bs->count_transfer_irq++; |
---|
| 286 | + |
---|
248 | 287 | /* fill in registers and fifos before enabling interrupts */ |
---|
249 | 288 | bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); |
---|
250 | 289 | bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); |
---|
.. | .. |
---|
268 | 307 | struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
---|
269 | 308 | unsigned long timeout; |
---|
270 | 309 | |
---|
| 310 | + /* update statistics */ |
---|
| 311 | + bs->count_transfer_polling++; |
---|
| 312 | + |
---|
271 | 313 | /* configure spi */ |
---|
272 | 314 | bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]); |
---|
273 | 315 | bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]); |
---|
274 | 316 | |
---|
275 | | - /* set the timeout */ |
---|
276 | | - timeout = jiffies + BCM2835_AUX_SPI_POLLING_JIFFIES; |
---|
| 317 | + /* set the timeout to at least 2 jiffies */ |
---|
| 318 | + timeout = jiffies + 2 + HZ * polling_limit_us / 1000000; |
---|
277 | 319 | |
---|
278 | 320 | /* loop until finished the transfer */ |
---|
279 | 321 | while (bs->rx_len) { |
---|
.. | .. |
---|
288 | 330 | jiffies - timeout, |
---|
289 | 331 | bs->tx_len, bs->rx_len); |
---|
290 | 332 | /* forward to interrupt handler */ |
---|
| 333 | + bs->count_transfer_irq_after_poll++; |
---|
291 | 334 | return __bcm2835aux_spi_transfer_one_irq(master, |
---|
292 | 335 | spi, tfr); |
---|
293 | 336 | } |
---|
.. | .. |
---|
303 | 346 | { |
---|
304 | 347 | struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
---|
305 | 348 | unsigned long spi_hz, clk_hz, speed; |
---|
306 | | - unsigned long spi_used_hz; |
---|
| 349 | + unsigned long hz_per_byte, byte_limit; |
---|
307 | 350 | |
---|
308 | 351 | /* calculate the registers to handle |
---|
309 | 352 | * |
---|
.. | .. |
---|
331 | 374 | /* set the new speed */ |
---|
332 | 375 | bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; |
---|
333 | 376 | |
---|
334 | | - spi_used_hz = clk_hz / (2 * (speed + 1)); |
---|
| 377 | + tfr->effective_speed_hz = clk_hz / (2 * (speed + 1)); |
---|
335 | 378 | |
---|
336 | 379 | /* set transmit buffers and length */ |
---|
337 | 380 | bs->tx_buf = tfr->tx_buf; |
---|
.. | .. |
---|
347 | 390 | * of Hz per byte per polling limit. E.g., we can transfer 1 byte in |
---|
348 | 391 | * 30 µs per 300,000 Hz of bus clock. |
---|
349 | 392 | */ |
---|
350 | | -#define HZ_PER_BYTE ((9 * 1000000) / BCM2835_AUX_SPI_POLLING_LIMIT_US) |
---|
| 393 | + hz_per_byte = polling_limit_us ? (9 * 1000000) / polling_limit_us : 0; |
---|
| 394 | + byte_limit = hz_per_byte ? tfr->effective_speed_hz / hz_per_byte : 1; |
---|
| 395 | + |
---|
351 | 396 | /* run in polling mode for short transfers */ |
---|
352 | | - if (tfr->len < spi_used_hz / HZ_PER_BYTE) |
---|
| 397 | + if (tfr->len < byte_limit) |
---|
353 | 398 | return bcm2835aux_spi_transfer_one_poll(master, spi, tfr); |
---|
354 | 399 | |
---|
355 | 400 | /* run in interrupt mode for all others */ |
---|
356 | 401 | return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); |
---|
357 | | -#undef HZ_PER_BYTE |
---|
358 | 402 | } |
---|
359 | 403 | |
---|
360 | 404 | static int bcm2835aux_spi_prepare_message(struct spi_master *master, |
---|
.. | .. |
---|
399 | 443 | bcm2835aux_spi_reset_hw(bs); |
---|
400 | 444 | } |
---|
401 | 445 | |
---|
| 446 | +static int bcm2835aux_spi_setup(struct spi_device *spi) |
---|
| 447 | +{ |
---|
| 448 | + int ret; |
---|
| 449 | + |
---|
| 450 | + /* sanity check for native cs */ |
---|
| 451 | + if (spi->mode & SPI_NO_CS) |
---|
| 452 | + return 0; |
---|
| 453 | + if (gpio_is_valid(spi->cs_gpio)) { |
---|
| 454 | + /* with gpio-cs set the GPIO to the correct level |
---|
| 455 | + * and as output (in case the dt has the gpio not configured |
---|
| 456 | + * as output but native cs) |
---|
| 457 | + */ |
---|
| 458 | + ret = gpio_direction_output(spi->cs_gpio, |
---|
| 459 | + (spi->mode & SPI_CS_HIGH) ? 0 : 1); |
---|
| 460 | + if (ret) |
---|
| 461 | + dev_err(&spi->dev, |
---|
| 462 | + "could not set gpio %i as output: %i\n", |
---|
| 463 | + spi->cs_gpio, ret); |
---|
| 464 | + |
---|
| 465 | + return ret; |
---|
| 466 | + } |
---|
| 467 | + |
---|
| 468 | + /* for dt-backwards compatibility: only support native on CS0 |
---|
| 469 | + * known things not supported with broken native CS: |
---|
| 470 | + * * multiple chip-selects: cs0-cs2 are all |
---|
| 471 | + * simultaniously asserted whenever there is a transfer |
---|
| 472 | + * this even includes SPI_NO_CS |
---|
| 473 | + * * SPI_CS_HIGH: cs are always asserted low |
---|
| 474 | + * * cs_change: cs is deasserted after each spi_transfer |
---|
| 475 | + * * cs_delay_usec: cs is always deasserted one SCK cycle |
---|
| 476 | + * after the last transfer |
---|
| 477 | + * probably more... |
---|
| 478 | + */ |
---|
| 479 | + dev_warn(&spi->dev, |
---|
| 480 | + "Native CS is not supported - please configure cs-gpio in device-tree\n"); |
---|
| 481 | + |
---|
| 482 | + if (spi->chip_select == 0) |
---|
| 483 | + return 0; |
---|
| 484 | + |
---|
| 485 | + dev_warn(&spi->dev, "Native CS is not working for cs > 0\n"); |
---|
| 486 | + |
---|
| 487 | + return -EINVAL; |
---|
| 488 | +} |
---|
| 489 | + |
---|
402 | 490 | static int bcm2835aux_spi_probe(struct platform_device *pdev) |
---|
403 | 491 | { |
---|
404 | 492 | struct spi_master *master; |
---|
405 | 493 | struct bcm2835aux_spi *bs; |
---|
406 | | - struct resource *res; |
---|
407 | 494 | unsigned long clk_hz; |
---|
408 | 495 | int err; |
---|
409 | 496 | |
---|
410 | 497 | master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs)); |
---|
411 | | - if (!master) { |
---|
412 | | - dev_err(&pdev->dev, "spi_alloc_master() failed\n"); |
---|
| 498 | + if (!master) |
---|
413 | 499 | return -ENOMEM; |
---|
414 | | - } |
---|
415 | 500 | |
---|
416 | 501 | platform_set_drvdata(pdev, master); |
---|
417 | 502 | master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); |
---|
.. | .. |
---|
428 | 513 | * a spi_transfer |
---|
429 | 514 | */ |
---|
430 | 515 | master->num_chipselect = 1; |
---|
| 516 | + master->setup = bcm2835aux_spi_setup; |
---|
431 | 517 | master->transfer_one = bcm2835aux_spi_transfer_one; |
---|
432 | 518 | master->handle_err = bcm2835aux_spi_handle_err; |
---|
433 | 519 | master->prepare_message = bcm2835aux_spi_prepare_message; |
---|
.. | .. |
---|
437 | 523 | bs = spi_master_get_devdata(master); |
---|
438 | 524 | |
---|
439 | 525 | /* the main area */ |
---|
440 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
441 | | - bs->regs = devm_ioremap_resource(&pdev->dev, res); |
---|
| 526 | + bs->regs = devm_platform_ioremap_resource(pdev, 0); |
---|
442 | 527 | if (IS_ERR(bs->regs)) |
---|
443 | 528 | return PTR_ERR(bs->regs); |
---|
444 | 529 | |
---|
445 | 530 | bs->clk = devm_clk_get(&pdev->dev, NULL); |
---|
446 | | - if ((!bs->clk) || (IS_ERR(bs->clk))) { |
---|
| 531 | + if (IS_ERR(bs->clk)) { |
---|
447 | 532 | err = PTR_ERR(bs->clk); |
---|
448 | 533 | dev_err(&pdev->dev, "could not get clk: %d\n", err); |
---|
449 | 534 | return err; |
---|
450 | 535 | } |
---|
451 | 536 | |
---|
452 | 537 | bs->irq = platform_get_irq(pdev, 0); |
---|
453 | | - if (bs->irq <= 0) { |
---|
454 | | - dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); |
---|
| 538 | + if (bs->irq <= 0) |
---|
455 | 539 | return bs->irq ? bs->irq : -ENODEV; |
---|
456 | | - } |
---|
457 | 540 | |
---|
458 | 541 | /* this also enables the HW block */ |
---|
459 | 542 | err = clk_prepare_enable(bs->clk); |
---|
.. | .. |
---|
488 | 571 | goto out_clk_disable; |
---|
489 | 572 | } |
---|
490 | 573 | |
---|
| 574 | + bcm2835aux_debugfs_create(bs, dev_name(&pdev->dev)); |
---|
| 575 | + |
---|
491 | 576 | return 0; |
---|
492 | 577 | |
---|
493 | 578 | out_clk_disable: |
---|
.. | .. |
---|
499 | 584 | { |
---|
500 | 585 | struct spi_master *master = platform_get_drvdata(pdev); |
---|
501 | 586 | struct bcm2835aux_spi *bs = spi_master_get_devdata(master); |
---|
| 587 | + |
---|
| 588 | + bcm2835aux_debugfs_remove(bs); |
---|
502 | 589 | |
---|
503 | 590 | spi_unregister_master(master); |
---|
504 | 591 | |
---|
.. | .. |
---|
528 | 615 | |
---|
529 | 616 | MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835 aux"); |
---|
530 | 617 | MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); |
---|
531 | | -MODULE_LICENSE("GPL v2"); |
---|
| 618 | +MODULE_LICENSE("GPL"); |
---|