Merge tag 'docs-5.11-2' of git://git.lwn.net/linux
[linux-2.6-microblaze.git] / drivers / spi / spi-rspi.c
index cbc2387..e39fd38 100644 (file)
 #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;