From: Sowjanya Komatineni <skomatineni@nvidia.com> To: thierry.reding@gmail.com, jonathanh@nvidia.com, talho@nvidia.com, skomatineni@nvidia.com, broonie@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com, kyarlagadda@nvidia.com Cc: ldewangan@nvidia.com, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH V3 9/9] spi: tegra114: add support for TX and RX trimmers Date: Mon, 15 Apr 2019 14:30:34 -0700 [thread overview] Message-ID: <1555363834-32155-10-git-send-email-skomatineni@nvidia.com> (raw) In-Reply-To: <1555363834-32155-1-git-send-email-skomatineni@nvidia.com> Tegra SPI master controller has programmable trimmers to adjust the data with respect to the clock. These trimmers are programmed in TX_CLK_TAP_DELAY and RX_CLK_TAP_DELAY fields of COMMAND2 register. SPI TX trimmer is to adjust the outgoing data with respect to the outgoing clock and SPI RX trimmer is to adjust the loopback clock with respect to the incoming data from the slave device. These trimmers vary based on trace lengths of the platform design for each of the slaves on the SPI bus and optimal value programmed is from the platform validation across PVT. This patch adds support for configuring TX and RX clock delay trimmers through the device tree properties. Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> --- drivers/spi/spi-tegra114.c | 68 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 8476a38cf4fb..20a413aef133 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -169,6 +169,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; @@ -208,8 +213,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; @@ -769,10 +776,13 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, 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 command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -839,7 +849,18 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, command1 &= ~SPI_CS_SW_VAL; } - tegra_spi_writel(tspi, 0, SPI_COMMAND2); + 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; + } + } else { command1 = tspi->command1_reg; command1 &= ~SPI_BIT_LENGTH(~0); @@ -895,9 +916,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; @@ -908,6 +962,11 @@ 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); @@ -1034,6 +1093,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; } @@ -1089,6 +1149,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; return IRQ_HANDLED; } @@ -1164,6 +1225,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; return IRQ_HANDLED; } @@ -1351,6 +1413,8 @@ static int tegra_spi_probe(struct platform_device *pdev) 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, @@ -1423,6 +1487,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); -- 2.7.4
WARNING: multiple messages have this Message-ID (diff)
From: Sowjanya Komatineni <skomatineni@nvidia.com> To: <thierry.reding@gmail.com>, <jonathanh@nvidia.com>, <talho@nvidia.com>, <skomatineni@nvidia.com>, <broonie@kernel.org>, <robh+dt@kernel.org>, <mark.rutland@arm.com>, <kyarlagadda@nvidia.com> Cc: <ldewangan@nvidia.com>, <linux-tegra@vger.kernel.org>, <linux-kernel@vger.kernel.org>, <linux-spi@vger.kernel.org>, <devicetree@vger.kernel.org> Subject: [PATCH V3 9/9] spi: tegra114: add support for TX and RX trimmers Date: Mon, 15 Apr 2019 14:30:34 -0700 [thread overview] Message-ID: <1555363834-32155-10-git-send-email-skomatineni@nvidia.com> (raw) In-Reply-To: <1555363834-32155-1-git-send-email-skomatineni@nvidia.com> Tegra SPI master controller has programmable trimmers to adjust the data with respect to the clock. These trimmers are programmed in TX_CLK_TAP_DELAY and RX_CLK_TAP_DELAY fields of COMMAND2 register. SPI TX trimmer is to adjust the outgoing data with respect to the outgoing clock and SPI RX trimmer is to adjust the loopback clock with respect to the incoming data from the slave device. These trimmers vary based on trace lengths of the platform design for each of the slaves on the SPI bus and optimal value programmed is from the platform validation across PVT. This patch adds support for configuring TX and RX clock delay trimmers through the device tree properties. Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> --- drivers/spi/spi-tegra114.c | 68 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 8476a38cf4fb..20a413aef133 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -169,6 +169,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; @@ -208,8 +213,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; @@ -769,10 +776,13 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, 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 command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -839,7 +849,18 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, command1 &= ~SPI_CS_SW_VAL; } - tegra_spi_writel(tspi, 0, SPI_COMMAND2); + 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; + } + } else { command1 = tspi->command1_reg; command1 &= ~SPI_BIT_LENGTH(~0); @@ -895,9 +916,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; @@ -908,6 +962,11 @@ 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); @@ -1034,6 +1093,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; } @@ -1089,6 +1149,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; return IRQ_HANDLED; } @@ -1164,6 +1225,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); + tspi->last_used_cs = master->num_chipselect + 1; return IRQ_HANDLED; } @@ -1351,6 +1413,8 @@ static int tegra_spi_probe(struct platform_device *pdev) 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, @@ -1423,6 +1487,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); -- 2.7.4
next prev parent reply other threads:[~2019-04-15 21:30 UTC|newest] Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-04-15 21:30 [PATCH V3 0/9] bug fixes and more features to Tegra SPI Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-15 21:30 ` [PATCH V3 1/9] spi: tegra114: fix PIO transfer Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-16 16:32 ` Applied "spi: tegra114: fix PIO transfer" to the spi tree Mark Brown 2019-04-16 16:32 ` Mark Brown 2019-04-16 16:32 ` Mark Brown 2019-04-16 16:32 ` Mark Brown 2019-04-29 21:42 ` Sowjanya Komatineni 2019-05-02 2:42 ` Mark Brown 2019-04-15 21:30 ` [PATCH V3 2/9] spi: expand mode support Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-18 10:26 ` Applied "spi: expand mode support" to the spi tree Mark Brown 2019-04-18 10:26 ` Mark Brown 2019-04-18 10:26 ` Mark Brown 2019-04-18 10:26 ` Mark Brown 2019-05-02 2:19 ` Mark Brown 2019-05-02 2:19 ` Mark Brown 2019-05-02 2:19 ` Mark Brown 2019-05-02 2:19 ` Mark Brown 2019-04-15 21:30 ` [PATCH V3 3/9] spi: add SPI_LSBYTE_FIRST mode Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-19 15:22 ` Mark Brown 2019-04-27 0:32 ` Sowjanya Komatineni 2019-05-06 4:49 ` Mark Brown 2019-04-15 21:30 ` [PATCH V3 4/9] spi: tegra114: add support for Tegra SPI LSBYTE_FIRST Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-15 21:30 ` [PATCH V3 5/9] spi: export spi core function spi_set_cs Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-19 15:18 ` Mark Brown 2019-04-29 22:02 ` Sowjanya Komatineni 2019-05-06 4:44 ` Mark Brown 2019-05-10 18:53 ` Sowjanya Komatineni 2019-05-12 3:12 ` Mark Brown 2019-04-15 21:30 ` [PATCH V3 6/9] spi: tegra114: add support for gpio based CS Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-15 21:30 ` [PATCH V3 7/9] spi: tegra114: add support for hw based cs Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-15 21:30 ` [PATCH V3 8/9] spi: tegra114: add support for HW CS timing Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni 2019-04-15 21:30 ` Sowjanya Komatineni [this message] 2019-04-15 21:30 ` [PATCH V3 9/9] spi: tegra114: add support for TX and RX trimmers Sowjanya Komatineni
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1555363834-32155-10-git-send-email-skomatineni@nvidia.com \ --to=skomatineni@nvidia.com \ --cc=broonie@kernel.org \ --cc=devicetree@vger.kernel.org \ --cc=jonathanh@nvidia.com \ --cc=kyarlagadda@nvidia.com \ --cc=ldewangan@nvidia.com \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-spi@vger.kernel.org \ --cc=linux-tegra@vger.kernel.org \ --cc=mark.rutland@arm.com \ --cc=robh+dt@kernel.org \ --cc=talho@nvidia.com \ --cc=thierry.reding@gmail.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.