diff options
Diffstat (limited to 'drivers/spi/spi-tegra114.c')
| -rw-r--r-- | drivers/spi/spi-tegra114.c | 67 | 
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e59ff7c1cee6..253a7f182fc9 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;  		} @@ -1351,6 +1410,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 +1484,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);  | 
