1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
From 33b150a792ccde6eded4240dea0e3ec784b07d7c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 15 Jan 2019 12:39:50 +0000
Subject: [PATCH] spi: spi-bcm2835: Re-enable HW CS
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/spi/spi-bcm2835.c | 53 +++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -1169,9 +1169,57 @@ static void bcm2835_spi_handle_err(struc
bcm2835_spi_reset_hw(ctlr);
}
-static int chip_match_name(struct gpio_chip *chip, void *data)
+static void bcm2835_spi_set_cs(struct spi_device *spi, bool gpio_level)
{
- return !strcmp(chip->label, data);
+ /*
+ * we can assume that we are "native" as per spi_set_cs
+ * calling us ONLY when cs_gpio is not set
+ * we can also assume that we are CS < 3 as per bcm2835_spi_setup
+ * we would not get called because of error handling there.
+ * the level passed is the electrical level not enabled/disabled
+ * so it has to get translated back to enable/disable
+ * see spi_set_cs in spi.c for the implementation
+ */
+
+ struct spi_master *master = spi->master;
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+ bool enable;
+
+ /* calculate the enable flag from the passed gpio_level */
+ enable = (spi->mode & SPI_CS_HIGH) ? gpio_level : !gpio_level;
+
+ /* set flags for "reverse" polarity in the registers */
+ if (spi->mode & SPI_CS_HIGH) {
+ /* set the correct CS-bits */
+ cs |= BCM2835_SPI_CS_CSPOL;
+ cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select;
+ } else {
+ /* clean the CS-bits */
+ cs &= ~BCM2835_SPI_CS_CSPOL;
+ cs &= ~(BCM2835_SPI_CS_CSPOL0 << spi->chip_select);
+ }
+
+ /* select the correct chip_select depending on disabled/enabled */
+ if (enable) {
+ /* set cs correctly */
+ if (spi->mode & SPI_NO_CS) {
+ /* use the "undefined" chip-select */
+ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
+ } else {
+ /* set the chip select */
+ cs &= ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01);
+ cs |= spi->chip_select;
+ }
+ } else {
+ /* disable CSPOL which puts HW-CS into deselected state */
+ cs &= ~BCM2835_SPI_CS_CSPOL;
+ /* use the "undefined" chip-select as precaution */
+ cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
+ }
+
+ /* finally set the calculated flags in SPI_CS */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs);
}
static int bcm2835_spi_setup(struct spi_device *spi)
@@ -1277,6 +1325,7 @@ static int bcm2835_spi_probe(struct plat
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->num_chipselect = BCM2835_SPI_NUM_CS;
ctlr->setup = bcm2835_spi_setup;
+ ctlr->set_cs = bcm2835_spi_set_cs;
ctlr->transfer_one = bcm2835_spi_transfer_one;
ctlr->handle_err = bcm2835_spi_handle_err;
ctlr->prepare_message = bcm2835_spi_prepare_message;
|