]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/spi/spi-tegra114.c
net: ethernet: broadcom: have drivers select DIMLIB as needed
[linux.git] / drivers / spi / spi-tegra114.c
index d22f4d10413fece73cd4bf5f0427e6ac34eac4e8..39374c2edcf3b810bdf3bed7b35935dde8349f9f 100644 (file)
                (reg = (((val) & 0x1) << ((cs) * 8 + 5)) |      \
                        ((reg) & ~(1 << ((cs) * 8 + 5))))
 #define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val)           \
-               (reg = (((val) & 0xF) << ((cs) * 8)) |          \
-                       ((reg) & ~(0xF << ((cs) * 8))))
+               (reg = (((val) & 0x1F) << ((cs) * 8)) |         \
+                       ((reg) & ~(0x1F << ((cs) * 8))))
+#define MAX_SETUP_HOLD_CYCLES                  16
+#define MAX_INACTIVE_CYCLES                    32
 
 #define SPI_TRANS_STATUS                       0x010
 #define SPI_BLK_CNT(val)                       (((val) >> 0) & 0xFFFF)
@@ -156,6 +158,11 @@ struct tegra_spi_soc_data {
        bool has_intr_mask_reg;
 };
 
+struct tegra_spi_client_data {
+       int tx_clk_tap_delay;
+       int rx_clk_tap_delay;
+};
+
 struct tegra_spi_data {
        struct device                           *dev;
        struct spi_master                       *master;
@@ -182,6 +189,7 @@ struct tegra_spi_data {
        unsigned                                dma_buf_size;
        unsigned                                max_buf_size;
        bool                                    is_curr_dma_xfer;
+       bool                                    use_hw_based_cs;
 
        struct completion                       rx_dma_complete;
        struct completion                       tx_dma_complete;
@@ -194,6 +202,10 @@ struct tegra_spi_data {
        u32                                     command1_reg;
        u32                                     dma_control_reg;
        u32                                     def_command1_reg;
+       u32                                     def_command2_reg;
+       u32                                     spi_cs_timing1;
+       u32                                     spi_cs_timing2;
+       u8                                      last_used_cs;
 
        struct completion                       xfer_completion;
        struct spi_transfer                     *curr_xfer;
@@ -711,14 +723,55 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
        dma_release_channel(dma_chan);
 }
 
+static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
+                                      u8 hold_dly, u8 inactive_dly)
+{
+       struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       u32 setup_hold;
+       u32 spi_cs_timing;
+       u32 inactive_cycles;
+       u8 cs_state;
+
+       setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
+       hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
+       if (setup_dly && hold_dly) {
+               setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
+               spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
+                                                 spi->chip_select,
+                                                 setup_hold);
+               if (tspi->spi_cs_timing1 != spi_cs_timing) {
+                       tspi->spi_cs_timing1 = spi_cs_timing;
+                       tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1);
+               }
+       }
+
+       inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+       if (inactive_cycles)
+               inactive_cycles--;
+       cs_state = inactive_cycles ? 0 : 1;
+       spi_cs_timing = tspi->spi_cs_timing2;
+       SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+                                         cs_state);
+       SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+                                      inactive_cycles);
+       if (tspi->spi_cs_timing2 != spi_cs_timing) {
+               tspi->spi_cs_timing2 = spi_cs_timing;
+               tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
+       }
+}
+
 static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
-               struct spi_transfer *t, bool is_first_of_msg)
+                                       struct spi_transfer *t,
+                                       bool is_first_of_msg,
+                                       bool is_single_xfer)
 {
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       struct tegra_spi_client_data *cdata = spi->controller_data;
        u32 speed = t->speed_hz;
        u8 bits_per_word = t->bits_per_word;
-       u32 command1;
+       u32 command1, command2;
        int req_mode;
+       u32 tx_tap = 0, rx_tap = 0;
 
        if (speed != tspi->cur_speed) {
                clk_set_rate(tspi->clk, speed);
@@ -765,13 +818,34 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
                } else
                        tegra_spi_writel(tspi, command1, SPI_COMMAND1);
 
-               command1 |= SPI_CS_SW_HW;
-               if (spi->mode & SPI_CS_HIGH)
-                       command1 |= SPI_CS_SW_VAL;
-               else
-                       command1 &= ~SPI_CS_SW_VAL;
+               /* GPIO based chip select control */
+               if (spi->cs_gpiod)
+                       gpiod_set_value(spi->cs_gpiod, 1);
+
+               if (is_single_xfer && !(t->cs_change)) {
+                       tspi->use_hw_based_cs = true;
+                       command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL);
+               } else {
+                       tspi->use_hw_based_cs = false;
+                       command1 |= SPI_CS_SW_HW;
+                       if (spi->mode & SPI_CS_HIGH)
+                               command1 |= SPI_CS_SW_VAL;
+                       else
+                               command1 &= ~SPI_CS_SW_VAL;
+               }
+
+               if (tspi->last_used_cs != spi->chip_select) {
+                       if (cdata && cdata->tx_clk_tap_delay)
+                               tx_tap = cdata->tx_clk_tap_delay;
+                       if (cdata && cdata->rx_clk_tap_delay)
+                               rx_tap = cdata->rx_clk_tap_delay;
+                       command2 = SPI_TX_TAP_DELAY(tx_tap) |
+                                  SPI_RX_TAP_DELAY(rx_tap);
+                       if (command2 != tspi->def_command2_reg)
+                               tegra_spi_writel(tspi, command2, SPI_COMMAND2);
+                       tspi->last_used_cs = spi->chip_select;
+               }
 
-               tegra_spi_writel(tspi, 0, SPI_COMMAND2);
        } else {
                command1 = tspi->command1_reg;
                command1 &= ~SPI_BIT_LENGTH(~0);
@@ -827,9 +901,42 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
        return ret;
 }
 
+static struct tegra_spi_client_data
+       *tegra_spi_parse_cdata_dt(struct spi_device *spi)
+{
+       struct tegra_spi_client_data *cdata;
+       struct device_node *slave_np;
+
+       slave_np = spi->dev.of_node;
+       if (!slave_np) {
+               dev_dbg(&spi->dev, "device node not found\n");
+               return NULL;
+       }
+
+       cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
+       if (!cdata)
+               return NULL;
+
+       of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay",
+                            &cdata->tx_clk_tap_delay);
+       of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay",
+                            &cdata->rx_clk_tap_delay);
+       return cdata;
+}
+
+static void tegra_spi_cleanup(struct spi_device *spi)
+{
+       struct tegra_spi_client_data *cdata = spi->controller_data;
+
+       spi->controller_data = NULL;
+       if (spi->dev.of_node)
+               kfree(cdata);
+}
+
 static int tegra_spi_setup(struct spi_device *spi)
 {
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+       struct tegra_spi_client_data *cdata = spi->controller_data;
        u32 val;
        unsigned long flags;
        int ret;
@@ -840,9 +947,16 @@ static int tegra_spi_setup(struct spi_device *spi)
                spi->mode & SPI_CPHA ? "" : "~",
                spi->max_speed_hz);
 
+       if (!cdata) {
+               cdata = tegra_spi_parse_cdata_dt(spi);
+               spi->controller_data = cdata;
+       }
+
        ret = pm_runtime_get_sync(tspi->dev);
        if (ret < 0) {
                dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+               if (cdata)
+                       tegra_spi_cleanup(spi);
                return ret;
        }
 
@@ -853,6 +967,10 @@ static int tegra_spi_setup(struct spi_device *spi)
        }
 
        spin_lock_irqsave(&tspi->lock, flags);
+       /* GPIO based chip select control */
+       if (spi->cs_gpiod)
+               gpiod_set_value(spi->cs_gpiod, 0);
+
        val = tspi->def_command1_reg;
        if (spi->mode & SPI_CS_HIGH)
                val &= ~SPI_CS_POL_INACTIVE(spi->chip_select);
@@ -882,11 +1000,18 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
        struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
        int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
 
-       if (cs_val)
-               tspi->command1_reg |= SPI_CS_SW_VAL;
-       else
-               tspi->command1_reg &= ~SPI_CS_SW_VAL;
-       tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       /* GPIO based chip select control */
+       if (spi->cs_gpiod)
+               gpiod_set_value(spi->cs_gpiod, 0);
+
+       if (!tspi->use_hw_based_cs) {
+               if (cs_val)
+                       tspi->command1_reg |= SPI_CS_SW_VAL;
+               else
+                       tspi->command1_reg &= ~SPI_CS_SW_VAL;
+               tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       }
+
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
 }
 
@@ -913,16 +1038,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
        struct spi_device *spi = msg->spi;
        int ret;
        bool skip = false;
+       int single_xfer;
 
        msg->status = 0;
        msg->actual_length = 0;
 
+       single_xfer = list_is_singular(&msg->transfers);
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                u32 cmd1;
 
                reinit_completion(&tspi->xfer_completion);
 
-               cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg);
+               cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg,
+                                                   single_xfer);
 
                if (!xfer->len) {
                        ret = 0;
@@ -955,6 +1083,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
                        reset_control_assert(tspi->rst);
                        udelay(2);
                        reset_control_deassert(tspi->rst);
+                       tspi->last_used_cs = master->num_chipselect + 1;
                        goto complete_xfer;
                }
 
@@ -1188,11 +1317,14 @@ static int tegra_spi_probe(struct platform_device *pdev)
                master->max_speed_hz = 25000000; /* 25MHz */
 
        /* the spi->mode bits understood by this driver: */
+       master->use_gpio_descriptors = true;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
                            SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->setup = tegra_spi_setup;
+       master->cleanup = tegra_spi_cleanup;
        master->transfer_one_message = tegra_spi_transfer_one_message;
+       master->set_cs_timing = tegra_spi_set_hw_cs_timing;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->auto_runtime_pm = true;
        bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
@@ -1268,6 +1400,10 @@ static int tegra_spi_probe(struct platform_device *pdev)
        reset_control_deassert(tspi->rst);
        tspi->def_command1_reg  = SPI_M_S;
        tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+       tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
+       tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
+       tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2);
+       tspi->last_used_cs = master->num_chipselect + 1;
        pm_runtime_put(&pdev->dev);
        ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
                                   tegra_spi_isr_thread, IRQF_ONESHOT,
@@ -1340,6 +1476,8 @@ static int tegra_spi_resume(struct device *dev)
                return ret;
        }
        tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+       tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2);
+       tspi->last_used_cs = master->num_chipselect + 1;
        pm_runtime_put(dev);
 
        return spi_master_resume(master);