From 33b150a792ccde6eded4240dea0e3ec784b07d7c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 15 Jan 2019 12:39:50 +0000 Subject: [PATCH] spi: spi-bcm2835: Re-enable HW CS Signed-off-by: Phil Elwell --- 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) @@ -1276,6 +1324,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;