diff options
Diffstat (limited to 'drivers/spi/spi-rspi.c')
-rw-r--r-- | drivers/spi/spi-rspi.c | 81 |
1 files changed, 52 insertions, 29 deletions
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index cbc2387d450c..e39fd38f5180 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -161,6 +161,7 @@ #define SPCMD_SPRW 0x0010 /* SPI Read/Write Access (Dual/Quad) */ #define SPCMD_SSLA(i) ((i) << 4) /* SSL Assert Signal Setting */ #define SPCMD_BRDV_MASK 0x000c /* Bit Rate Division Setting */ +#define SPCMD_BRDV(brdv) ((brdv) << 2) #define SPCMD_CPOL 0x0002 /* Clock Polarity Setting */ #define SPCMD_CPHA 0x0001 /* Clock Phase Setting */ @@ -242,24 +243,40 @@ struct spi_ops { int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer); u16 extra_mode_bits; + u16 min_div; + u16 max_div; u16 flags; u16 fifo_size; u8 num_hw_ss; }; +static void rspi_set_rate(struct rspi_data *rspi) +{ + unsigned long clksrc; + int brdv = 0, spbr; + + clksrc = clk_get_rate(rspi->clk); + spbr = DIV_ROUND_UP(clksrc, 2 * rspi->speed_hz) - 1; + while (spbr > 255 && brdv < 3) { + brdv++; + spbr = DIV_ROUND_UP(spbr + 1, 2) - 1; + } + + rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + rspi->spcmd |= SPCMD_BRDV(brdv); + rspi->speed_hz = DIV_ROUND_UP(clksrc, (2U << brdv) * (spbr + 1)); +} + /* * functions for RSPI on legacy SH */ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) { - int spbr; - /* Sets output mode, MOSI signal, and (optionally) loopback */ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ - spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), 2 * rspi->speed_hz) - 1; - rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + rspi_set_rate(rspi); /* Disable dummy transmission, set 16-bit word access, 1 frame */ rspi_write8(rspi, 0, RSPI_SPDCR); @@ -289,25 +306,11 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) */ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) { - int spbr; - int div = 0; - unsigned long clksrc; - /* Sets output mode, MOSI signal, and (optionally) loopback */ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); - clksrc = clk_get_rate(rspi->clk); - while (div < 3) { - if (rspi->speed_hz >= clksrc/4) /* 4=(CLK/2)/2 */ - break; - div++; - clksrc /= 2; - } - /* Sets transfer bit rate */ - spbr = DIV_ROUND_UP(clksrc, 2 * rspi->speed_hz) - 1; - rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); - rspi->spcmd |= div << 2; + rspi_set_rate(rspi); /* Disable dummy transmission, set byte access */ rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR); @@ -334,14 +337,28 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) */ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) { - int spbr; + unsigned long clksrc; + int brdv = 0, spbr; /* Sets output mode, MOSI signal, and (optionally) loopback */ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ - spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), 2 * rspi->speed_hz); - rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + clksrc = clk_get_rate(rspi->clk); + if (rspi->speed_hz >= clksrc) { + spbr = 0; + rspi->speed_hz = clksrc; + } else { + spbr = DIV_ROUND_UP(clksrc, 2 * rspi->speed_hz); + while (spbr > 255 && brdv < 3) { + brdv++; + spbr = DIV_ROUND_UP(spbr, 2); + } + spbr = clamp(spbr, 0, 255); + rspi->speed_hz = DIV_ROUND_UP(clksrc, (2U << brdv) * spbr); + } + rspi_write8(rspi, spbr, RSPI_SPBR); + rspi->spcmd |= SPCMD_BRDV(brdv); /* Disable dummy transmission, set byte access */ rspi_write8(rspi, 0, RSPI_SPDCR); @@ -686,6 +703,8 @@ static int rspi_common_transfer(struct rspi_data *rspi, { int ret; + xfer->effective_speed_hz = rspi->speed_hz; + ret = rspi_dma_check_then_transfer(rspi, xfer); if (ret != -EAGAIN) return ret; @@ -841,6 +860,7 @@ static int qspi_transfer_one(struct spi_controller *ctlr, { struct rspi_data *rspi = spi_controller_get_devdata(ctlr); + xfer->effective_speed_hz = rspi->speed_hz; if (spi->mode & SPI_LOOP) { return qspi_transfer_out_in(rspi, xfer); } else if (xfer->tx_nbits > SPI_NBITS_SINGLE) { @@ -1163,6 +1183,8 @@ static int rspi_remove(struct platform_device *pdev) static const struct spi_ops rspi_ops = { .set_config_register = rspi_set_config_register, .transfer_one = rspi_transfer_one, + .min_div = 2, + .max_div = 4096, .flags = SPI_CONTROLLER_MUST_TX, .fifo_size = 8, .num_hw_ss = 2, @@ -1171,6 +1193,8 @@ static const struct spi_ops rspi_ops = { static const struct spi_ops rspi_rz_ops = { .set_config_register = rspi_rz_set_config_register, .transfer_one = rspi_rz_transfer_one, + .min_div = 2, + .max_div = 4096, .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, .fifo_size = 8, /* 8 for TX, 32 for RX */ .num_hw_ss = 1, @@ -1181,6 +1205,8 @@ static const struct spi_ops qspi_ops = { .transfer_one = qspi_transfer_one, .extra_mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD, + .min_div = 1, + .max_div = 4080, .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, .fifo_size = 32, .num_hw_ss = 1, @@ -1242,6 +1268,7 @@ static int rspi_probe(struct platform_device *pdev) int ret; const struct rspi_plat_data *rspi_pd; const struct spi_ops *ops; + unsigned long clksrc; ctlr = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); if (ctlr == NULL) @@ -1261,13 +1288,6 @@ static int rspi_probe(struct platform_device *pdev) ctlr->num_chipselect = 2; /* default */ } - /* ops parameter check */ - if (!ops->set_config_register) { - dev_err(&pdev->dev, "there is no set_config_register\n"); - ret = -ENODEV; - goto error1; - } - rspi = spi_controller_get_devdata(ctlr); platform_set_drvdata(pdev, rspi); rspi->ops = ops; @@ -1301,6 +1321,9 @@ static int rspi_probe(struct platform_device *pdev) ctlr->unprepare_message = rspi_unprepare_message; ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_LOOP | ops->extra_mode_bits; + clksrc = clk_get_rate(rspi->clk); + ctlr->min_speed_hz = DIV_ROUND_UP(clksrc, ops->max_div); + ctlr->max_speed_hz = DIV_ROUND_UP(clksrc, ops->min_div); ctlr->flags = ops->flags; ctlr->dev.of_node = pdev->dev.of_node; ctlr->use_gpio_descriptors = true; |