mirror of
https://github.com/torvalds/linux.git
synced 2024-12-02 00:51:44 +00:00
Merge series "spi: rspi: Bit rate improvements" from Geert Uytterhoeven <geert+renesas@glider.be>:
Hi Mark, This patch series contains several improvements for the Renesas SPI/QSPI driver related to bit rate configuration. Changes compared to v1 (https://lore.kernel.org/r/20200608095940.30516-1-geert+renesas@glider.be): - Drop accepted patch. This has been tested on RSK+RZA1 (RSPI) and R-Car M2-W/Koelsch (QSPI), using a scope and logic analyzer, except for the by-one divider on QSPI. This has not been tested on legacy SuperH, due to lack of hardware. Thanks for your comments! Geert Uytterhoeven (7): spi: rspi: Remove useless .set_config_register() check spi: rspi: Clean up Bit Rate Division Setting handling spi: rspi: Increase bit rate accuracy on RZ/A spi: rspi: Increase bit rate range for RSPI on SH spi: rspi: Increase bit rate range for QSPI spi: rspi: Fill in spi_transfer.effective_speed_hz spi: rspi: Fill in controller speed limits drivers/spi/spi-rspi.c | 81 +++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 29 deletions(-) -- 2.17.1 Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
This commit is contained in:
commit
6a23e577a9
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user