Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp5935144yba; Mon, 13 May 2019 21:33:51 -0700 (PDT) X-Google-Smtp-Source: APXvYqw3ofnPcfeoo6TVqmIyd7QPwU+Ziv+HmohwMYwZP8l0x4S2946MH/Z+E7uXOQ6eGlmFYGdI X-Received: by 2002:a17:902:184:: with SMTP id b4mr9449919plb.2.1557808431792; Mon, 13 May 2019 21:33:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1557808431; cv=none; d=google.com; s=arc-20160816; b=IYkkLLs5dJhEvqcK2dRD5fhfoYWzh0oKogiHpU2qXljAQkBId2XqsWDlX3VNxqImKN mV+MHRDWjChMb24bIN/EsDkKvtUop4lAg0S05azX5TfCJNQ2+RNG/5ei9G3JxwHf3PAd oTemB0FKlze1BmouwlW2OeQjijrldqIhtxBvXYq92RRwmcXtcut0nCol3o0Z3UYe2wfj bZLNKNXLSNXkQ0vaeByyEZhbQoNfXGp2j0f6PO87TMXPFebKoBIwQMnMX1FMc4uyTLF7 1XCSXrrNEp1B8I3oMVW+tu5oHNxx9R6SjeqtYnu1Vata53Tr+I5K6LMM/IjzmIW7c0S9 +j8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:dkim-signature:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from; bh=TzUWK//3MRAdJiwzKWtB//s3TMI0R62fex2bv33Nno0=; b=m9wFDoKCzxKB9Rgzpa91hNmiAJTGMJ+Q8ktCk6vIV7aYLYRG8x7+hK7fWiZzl+p2Pt t66yRgCk1rHi2V2MoxOKAmq9Kk+uw+cQ/v4cHIWAlWjP5jfnGnfqnEDyFxBASuY/RbOi jDZC7X/0EoALTFpGt0gg4muKf0Y6ufSX5J8XRgZANIcCDPvkraQe3VzWdKjzHIjlz5NK 4uxr+m4YYjwDPB2HIXwPM5PxJkhzqvLbmiRd6ugOD5AKLO+C85dwwUR7bBpfBaAAroHb JCTHfssoS21pm+jsUK8vqkWYaODMMWbTlDZcdqpsBAPIfRKoQNU54udPKo4aR6gHsxAM V0pA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nvidia.com header.s=n1 header.b=VtmceA0J; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nvidia.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i20si18685078pfr.279.2019.05.13.21.33.25; Mon, 13 May 2019 21:33:51 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nvidia.com header.s=n1 header.b=VtmceA0J; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nvidia.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726758AbfENEcJ (ORCPT + 99 others); Tue, 14 May 2019 00:32:09 -0400 Received: from hqemgate15.nvidia.com ([216.228.121.64]:15844 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726389AbfENEcD (ORCPT ); Tue, 14 May 2019 00:32:03 -0400 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Mon, 13 May 2019 21:31:21 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Mon, 13 May 2019 21:32:01 -0700 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Mon, 13 May 2019 21:32:01 -0700 Received: from HQMAIL107.nvidia.com (172.20.187.13) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Tue, 14 May 2019 04:32:01 +0000 Received: from hqnvemgw02.nvidia.com (172.16.227.111) by HQMAIL107.nvidia.com (172.20.187.13) with Microsoft SMTP Server (TLS) id 15.0.1473.3 via Frontend Transport; Tue, 14 May 2019 04:31:59 +0000 Received: from skomatineni-linux.nvidia.com (Not Verified[10.2.164.159]) by hqnvemgw02.nvidia.com with Trustwave SEG (v7,5,8,10121) id ; Mon, 13 May 2019 21:32:00 -0700 From: Sowjanya Komatineni To: , , , CC: , , , Sowjanya Komatineni Subject: [PATCH V4 4/4] spi: tegra114: add support for TX and RX trimmers Date: Mon, 13 May 2019 21:31:52 -0700 Message-ID: <1557808312-3213-4-git-send-email-skomatineni@nvidia.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1557808312-3213-1-git-send-email-skomatineni@nvidia.com> References: <1557808312-3213-1-git-send-email-skomatineni@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 Content-Type: text/plain DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1557808281; bh=TzUWK//3MRAdJiwzKWtB//s3TMI0R62fex2bv33Nno0=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: Content-Type; b=VtmceA0JiHjkgW3DXwc3y1Pd1wOqribSz4YppdVXm2VhYhxDfRsC8Jb71evm2CtwQ J7znxF45QL37QSXYmbHeWPaIxW1lD3oDaFDSrZvSOCEVqRW0YHFonWTNMmwhr7Tdy7 EP6FSu32SPQcci7DvNdLKoyIWaBY1ahHLpgVYtRee5mPwKYrrWGpXM3fmsHPou34R6 //VQ81/J6NPWbqVZFYbboDTp4YmNo4cPn+Q9tZuenQzPh1Yni1qvVfP0mK4bB5KV70 /E4WmrV21vCVJZWa7MfQriL7vXX72ujWlmmr4ICE4UGXdmmi6/N8rO0K69v0UTcaDj R7DIlLZc5tdAA== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- drivers/spi/spi-tegra114.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e59ff7c1cee6..377fcc026794 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; @@ -770,10 +777,12 @@ 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 command1, command2; int req_mode; + u32 tx_tap = 0, rx_tap = 0; if (speed != tspi->cur_speed) { clk_set_rate(tspi->clk, speed); @@ -836,7 +845,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); @@ -892,9 +912,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; @@ -905,6 +958,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 +1092,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 +1148,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 +1224,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 +1412,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 +1486,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