]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi-sirf.c
Merge remote-tracking branches 'spi/topic/pl022', 'spi/topic/pxa2xx', 'spi/topic...
[karo-tx-linux.git] / drivers / spi / spi-sirf.c
index 95ac276eaafe6ab7a6c1f6b82aede8bad00bdac0..39e2c0a55a2865acc6c50354cf90fa27263bc922 100644 (file)
 #define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26)
 #define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26)
 #define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26)
-#define SIRFSOC_SPI_CMD_BYTE_NUM(x)            ((x & 3) << 28)
-#define SIRFSOC_SPI_ENA_AUTO_CLR               BIT(30)
-#define SIRFSOC_SPI_MUL_DAT_MODE               BIT(31)
+#define SIRFSOC_SPI_CMD_BYTE_NUM(x)    ((x & 3) << 28)
+#define SIRFSOC_SPI_ENA_AUTO_CLR       BIT(30)
+#define SIRFSOC_SPI_MUL_DAT_MODE       BIT(31)
 
 /* Interrupt Enable */
-#define SIRFSOC_SPI_RX_DONE_INT_EN             BIT(0)
-#define SIRFSOC_SPI_TX_DONE_INT_EN             BIT(1)
-#define SIRFSOC_SPI_RX_OFLOW_INT_EN            BIT(2)
-#define SIRFSOC_SPI_TX_UFLOW_INT_EN            BIT(3)
+#define SIRFSOC_SPI_RX_DONE_INT_EN     BIT(0)
+#define SIRFSOC_SPI_TX_DONE_INT_EN     BIT(1)
+#define SIRFSOC_SPI_RX_OFLOW_INT_EN    BIT(2)
+#define SIRFSOC_SPI_TX_UFLOW_INT_EN    BIT(3)
 #define SIRFSOC_SPI_RX_IO_DMA_INT_EN   BIT(4)
 #define SIRFSOC_SPI_TX_IO_DMA_INT_EN   BIT(5)
 #define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6)
@@ -79,7 +79,7 @@
 #define SIRFSOC_SPI_TXFIFO_THD_INT_EN  BIT(9)
 #define SIRFSOC_SPI_FRM_END_INT_EN     BIT(10)
 
-#define SIRFSOC_SPI_INT_MASK_ALL               0x1FFF
+#define SIRFSOC_SPI_INT_MASK_ALL       0x1FFF
 
 /* Interrupt status */
 #define SIRFSOC_SPI_RX_DONE            BIT(0)
@@ -170,8 +170,7 @@ struct sirfsoc_spi {
         * command model
         */
        bool    tx_by_cmd;
-
-       int chipselect[0];
+       bool    hw_cs;
 };
 
 static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi)
@@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data)
        complete(dma_complete);
 }
 
-static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
+static void spi_sirfsoc_cmd_transfer(struct spi_device *spi,
        struct spi_transfer *t)
 {
        struct sirfsoc_spi *sspi;
@@ -312,6 +311,8 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
        u32 cmd;
 
        sspi = spi_master_get_devdata(spi->master);
+       writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
+       writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
        memcpy(&cmd, sspi->tx, t->len);
        if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
                cmd = cpu_to_be32(cmd) >>
@@ -326,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
                sspi->base + SIRFSOC_SPI_TX_RX_EN);
        if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
                dev_err(&spi->dev, "cmd transfer timeout\n");
-               return 0;
+               return;
        }
-
-       return t->len;
+       sspi->left_rx_word -= t->len;
 }
 
 static void spi_sirfsoc_dma_transfer(struct spi_device *spi,
@@ -438,7 +438,8 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi,
                        sspi->tx_word(sspi);
                writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN |
                        SIRFSOC_SPI_TX_UFLOW_INT_EN |
-                       SIRFSOC_SPI_RX_OFLOW_INT_EN,
+                       SIRFSOC_SPI_RX_OFLOW_INT_EN |
+                       SIRFSOC_SPI_RX_IO_DMA_INT_EN,
                        sspi->base + SIRFSOC_SPI_INT_EN);
                writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
                        sspi->base + SIRFSOC_SPI_TX_RX_EN);
@@ -484,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
 {
        struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master);
 
-       if (sspi->chipselect[spi->chip_select] == 0) {
+       if (sspi->hw_cs) {
                u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
                switch (value) {
                case BITBANG_CS_ACTIVE:
@@ -502,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
                }
                writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
        } else {
-               int gpio = sspi->chipselect[spi->chip_select];
                switch (value) {
                case BITBANG_CS_ACTIVE:
-                       gpio_direction_output(gpio,
+                       gpio_direction_output(spi->cs_gpio,
                                        spi->mode & SPI_CS_HIGH ? 1 : 0);
                        break;
                case BITBANG_CS_INACTIVE:
-                       gpio_direction_output(gpio,
+                       gpio_direction_output(spi->cs_gpio,
                                        spi->mode & SPI_CS_HIGH ? 0 : 1);
                        break;
                }
@@ -603,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                sspi->tx_by_cmd = false;
        }
        /*
-        * set spi controller in RISC chipselect mode, we are controlling CS by
-        * software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE.
+        * it should never set to hardware cs mode because in hardware cs mode,
+        * cs signal can't controlled by driver.
         */
        regval |= SIRFSOC_SPI_CS_IO_MODE;
        writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
@@ -627,9 +627,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 
 static int spi_sirfsoc_setup(struct spi_device *spi)
 {
+       struct sirfsoc_spi *sspi;
+
        if (!spi->max_speed_hz)
                return -EINVAL;
 
+       sspi = spi_master_get_devdata(spi->master);
+
+       if (spi->cs_gpio == -ENOENT)
+               sspi->hw_cs = true;
+       else
+               sspi->hw_cs = false;
        return spi_sirfsoc_setup_transfer(spi, NULL);
 }
 
@@ -638,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        struct sirfsoc_spi *sspi;
        struct spi_master *master;
        struct resource *mem_res;
-       int num_cs, cs_gpio, irq;
-       int i;
-       int ret;
+       int irq;
+       int i, ret;
 
-       ret = of_property_read_u32(pdev->dev.of_node,
-                       "sirf,spi-num-chipselects", &num_cs);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Unable to get chip select number\n");
-               goto err_cs;
-       }
-
-       master = spi_alloc_master(&pdev->dev,
-                       sizeof(*sspi) + sizeof(int) * num_cs);
+       master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
        if (!master) {
                dev_err(&pdev->dev, "Unable to allocate SPI master\n");
                return -ENOMEM;
@@ -658,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
        sspi = spi_master_get_devdata(master);
 
-       master->num_chipselect = num_cs;
-
-       for (i = 0; i < master->num_chipselect; i++) {
-               cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
-               if (cs_gpio < 0) {
-                       dev_err(&pdev->dev, "can't get cs gpio from DT\n");
-                       ret = -ENODEV;
-                       goto free_master;
-               }
-
-               sspi->chipselect[i] = cs_gpio;
-               if (cs_gpio == 0)
-                       continue; /* use cs from spi controller */
-
-               ret = gpio_request(cs_gpio, DRIVER_NAME);
-               if (ret) {
-                       while (i > 0) {
-                               i--;
-                               if (sspi->chipselect[i] > 0)
-                                       gpio_free(sspi->chipselect[i]);
-                       }
-                       dev_err(&pdev->dev, "fail to request cs gpios\n");
-                       goto free_master;
-               }
-       }
-
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(sspi->base)) {
@@ -753,7 +726,21 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        ret = spi_bitbang_start(&sspi->bitbang);
        if (ret)
                goto free_dummypage;
-
+       for (i = 0; master->cs_gpios && i < master->num_chipselect; i++) {
+               if (master->cs_gpios[i] == -ENOENT)
+                       continue;
+               if (!gpio_is_valid(master->cs_gpios[i])) {
+                       dev_err(&pdev->dev, "no valid gpio\n");
+                       ret = -EINVAL;
+                       goto free_dummypage;
+               }
+               ret = devm_gpio_request(&pdev->dev,
+                               master->cs_gpios[i], DRIVER_NAME);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request gpio\n");
+                       goto free_dummypage;
+               }
+       }
        dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
 
        return 0;
@@ -768,7 +755,7 @@ free_rx_dma:
        dma_release_channel(sspi->rx_chan);
 free_master:
        spi_master_put(master);
-err_cs:
+
        return ret;
 }
 
@@ -776,16 +763,11 @@ static int  spi_sirfsoc_remove(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct sirfsoc_spi *sspi;
-       int i;
 
        master = platform_get_drvdata(pdev);
        sspi = spi_master_get_devdata(master);
 
        spi_bitbang_stop(&sspi->bitbang);
-       for (i = 0; i < master->num_chipselect; i++) {
-               if (sspi->chipselect[i] > 0)
-                       gpio_free(sspi->chipselect[i]);
-       }
        kfree(sspi->dummypage);
        clk_disable_unprepare(sspi->clk);
        clk_put(sspi->clk);