diff options
Diffstat (limited to 'drivers/spi/spi-tegra20-slink.c')
| -rw-r--r-- | drivers/spi/spi-tegra20-slink.c | 257 |
1 files changed, 114 insertions, 143 deletions
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 1427f343b39a..fe452d03c1ee 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI driver for Nvidia's Tegra20/Tegra30 SLINK Controller. * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> @@ -29,12 +18,14 @@ #include <linux/kthread.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/reset.h> #include <linux/spi/spi.h> +#include <soc/tegra/common.h> + #define SLINK_COMMAND 0x000 #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) #define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5) @@ -161,7 +152,7 @@ struct tegra_slink_chip_data { struct tegra_slink_data { struct device *dev; - struct spi_master *master; + struct spi_controller *host; const struct tegra_slink_chip_data *chip_data; spinlock_t lock; @@ -215,9 +206,6 @@ struct tegra_slink_data { struct dma_async_tx_descriptor *tx_dma_desc; }; -static int tegra_slink_runtime_suspend(struct device *dev); -static int tegra_slink_runtime_resume(struct device *dev); - static inline u32 tegra_slink_readl(struct tegra_slink_data *tspi, unsigned long reg) { @@ -554,7 +542,7 @@ static int tegra_slink_start_dma_based_transfer( if (tspi->is_packed) { val |= SLINK_PACKED; tegra_slink_writel(tspi, val, SLINK_DMA_CTL); - /* HW need small delay after settign Packed mode */ + /* HW need small delay after setting Packed mode */ udelay(1); } tspi->dma_control_reg = val; @@ -610,15 +598,10 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi, int ret; struct dma_slave_config dma_sconfig; - dma_chan = dma_request_slave_channel_reason(tspi->dev, - dma_to_memory ? "rx" : "tx"); - if (IS_ERR(dma_chan)) { - ret = PTR_ERR(dma_chan); - if (ret != -EPROBE_DEFER) - dev_err(tspi->dev, - "Dma channel is not available: %d\n", ret); - return ret; - } + dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) + return dev_err_probe(tspi->dev, PTR_ERR(dma_chan), + "Dma channel is not available\n"); dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size, &dma_phys, GFP_KERNEL); @@ -688,7 +671,7 @@ static void tegra_slink_deinit_dma_param(struct tegra_slink_data *tspi, static int tegra_slink_start_transfer_one(struct spi_device *spi, struct spi_transfer *t) { - struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_slink_data *tspi = spi_controller_get_devdata(spi->controller); u32 speed; u8 bits_per_word; unsigned total_fifo_words; @@ -699,7 +682,7 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, bits_per_word = t->bits_per_word; speed = t->speed_hz; if (speed != tspi->cur_speed) { - clk_set_rate(tspi->clk, speed * 4); + dev_pm_opp_set_rate(tspi->dev, speed * 4); tspi->cur_speed = speed; } @@ -717,9 +700,6 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, command2 = tspi->command2_reg; command2 &= ~(SLINK_RXEN | SLINK_TXEN); - tegra_slink_writel(tspi, command, SLINK_COMMAND); - tspi->command_reg = command; - tspi->cur_direction = 0; if (t->rx_buf) { command2 |= SLINK_RXEN; @@ -729,9 +709,18 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, command2 |= SLINK_TXEN; tspi->cur_direction |= DATA_DIR_TX; } + + /* + * Writing to the command2 register bevore the command register prevents + * a spike in chip_select line 0. This selects the chip_select line + * before changing the chip_select value. + */ tegra_slink_writel(tspi, command2, SLINK_COMMAND2); tspi->command2_reg = command2; + tegra_slink_writel(tspi, command, SLINK_COMMAND); + tspi->command_reg = command; + if (total_fifo_words > SLINK_FIFO_DEPTH) ret = tegra_slink_start_dma_based_transfer(tspi, t); else @@ -748,7 +737,7 @@ static int tegra_slink_setup(struct spi_device *spi) SLINK_CS_POLARITY3, }; - struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master); + struct tegra_slink_data *tspi = spi_controller_get_devdata(spi->controller); u32 val; unsigned long flags; int ret; @@ -759,7 +748,7 @@ static int tegra_slink_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); - ret = pm_runtime_get_sync(tspi->dev); + ret = pm_runtime_resume_and_get(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); return ret; @@ -768,9 +757,9 @@ static int tegra_slink_setup(struct spi_device *spi) spin_lock_irqsave(&tspi->lock, flags); val = tspi->def_command_reg; if (spi->mode & SPI_CS_HIGH) - val |= cs_pol_bit[spi->chip_select]; + val |= cs_pol_bit[spi_get_chipselect(spi, 0)]; else - val &= ~cs_pol_bit[spi->chip_select]; + val &= ~cs_pol_bit[spi_get_chipselect(spi, 0)]; tspi->def_command_reg = val; tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); spin_unlock_irqrestore(&tspi->lock, flags); @@ -779,10 +768,10 @@ static int tegra_slink_setup(struct spi_device *spi) return 0; } -static int tegra_slink_prepare_message(struct spi_master *master, +static int tegra_slink_prepare_message(struct spi_controller *host, struct spi_message *msg) { - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); struct spi_device *spi = msg->spi; tegra_slink_clear_status(tspi); @@ -791,7 +780,7 @@ static int tegra_slink_prepare_message(struct spi_master *master, tspi->command_reg |= SLINK_CS_SW | SLINK_CS_VALUE; tspi->command2_reg = tspi->def_command2_reg; - tspi->command2_reg |= SLINK_SS_EN_CS(spi->chip_select); + tspi->command2_reg |= SLINK_SS_EN_CS(spi_get_chipselect(spi, 0)); tspi->command_reg &= ~SLINK_MODES; if (spi->mode & SPI_CPHA) @@ -805,11 +794,11 @@ static int tegra_slink_prepare_message(struct spi_master *master, return 0; } -static int tegra_slink_transfer_one(struct spi_master *master, +static int tegra_slink_transfer_one(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *xfer) { - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); int ret; reinit_completion(&tspi->xfer_completion); @@ -836,10 +825,10 @@ static int tegra_slink_transfer_one(struct spi_master *master, return 0; } -static int tegra_slink_unprepare_message(struct spi_master *master, +static int tegra_slink_unprepare_message(struct spi_controller *host, struct spi_message *msg) { - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); @@ -1010,101 +999,72 @@ MODULE_DEVICE_TABLE(of, tegra_slink_of_match); static int tegra_slink_probe(struct platform_device *pdev) { - struct spi_master *master; + struct spi_controller *host; struct tegra_slink_data *tspi; struct resource *r; int ret, spi_irq; const struct tegra_slink_chip_data *cdata = NULL; - const struct of_device_id *match; - match = of_match_device(tegra_slink_of_match, &pdev->dev); - if (!match) { - dev_err(&pdev->dev, "Error: No device match found\n"); - return -ENODEV; - } - cdata = match->data; + cdata = of_device_get_match_data(&pdev->dev); - master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); - if (!master) { - dev_err(&pdev->dev, "master allocation failed\n"); + host = spi_alloc_host(&pdev->dev, sizeof(*tspi)); + if (!host) { + dev_err(&pdev->dev, "host allocation failed\n"); return -ENOMEM; } /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - master->setup = tegra_slink_setup; - master->prepare_message = tegra_slink_prepare_message; - master->transfer_one = tegra_slink_transfer_one; - master->unprepare_message = tegra_slink_unprepare_message; - master->auto_runtime_pm = true; - master->num_chipselect = MAX_CHIP_SELECT; - - platform_set_drvdata(pdev, master); - tspi = spi_master_get_devdata(master); - tspi->master = master; + host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + host->setup = tegra_slink_setup; + host->prepare_message = tegra_slink_prepare_message; + host->transfer_one = tegra_slink_transfer_one; + host->unprepare_message = tegra_slink_unprepare_message; + host->auto_runtime_pm = true; + host->num_chipselect = MAX_CHIP_SELECT; + + platform_set_drvdata(pdev, host); + tspi = spi_controller_get_devdata(host); + tspi->host = host; tspi->dev = &pdev->dev; tspi->chip_data = cdata; spin_lock_init(&tspi->lock); if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency", - &master->max_speed_hz)) - master->max_speed_hz = 25000000; /* 25MHz */ - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(&pdev->dev, "No IO memory resource\n"); - ret = -ENODEV; - goto exit_free_master; - } - tspi->phys = r->start; - tspi->base = devm_ioremap_resource(&pdev->dev, r); + &host->max_speed_hz)) + host->max_speed_hz = 25000000; /* 25MHz */ + + tspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); if (IS_ERR(tspi->base)) { ret = PTR_ERR(tspi->base); - goto exit_free_master; + goto exit_free_host; } + tspi->phys = r->start; /* disabled clock may cause interrupt storm upon request */ tspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(tspi->clk)) { ret = PTR_ERR(tspi->clk); dev_err(&pdev->dev, "Can not get clock %d\n", ret); - goto exit_free_master; - } - ret = clk_prepare(tspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "Clock prepare failed %d\n", ret); - goto exit_free_master; - } - ret = clk_enable(tspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "Clock enable failed %d\n", ret); - goto exit_free_master; - } - - spi_irq = platform_get_irq(pdev, 0); - tspi->irq = spi_irq; - ret = request_threaded_irq(tspi->irq, tegra_slink_isr, - tegra_slink_isr_thread, IRQF_ONESHOT, - dev_name(&pdev->dev), tspi); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", - tspi->irq); - goto exit_clk_disable; + goto exit_free_host; } tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tspi->rst); - goto exit_free_irq; + goto exit_free_host; } + ret = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (ret) + goto exit_free_host; + tspi->max_buf_size = SLINK_FIFO_DEPTH << 2; tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN; ret = tegra_slink_init_dma_param(tspi, true); if (ret < 0) - goto exit_free_irq; + goto exit_free_host; ret = tegra_slink_init_dma_param(tspi, false); if (ret < 0) goto exit_rx_dma_free; @@ -1115,55 +1075,70 @@ static int tegra_slink_probe(struct platform_device *pdev) init_completion(&tspi->xfer_completion); pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra_slink_runtime_resume(&pdev->dev); - if (ret) - goto exit_pm_disable; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); + goto exit_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); + reset_control_assert(tspi->rst); + udelay(2); + reset_control_deassert(tspi->rst); + + spi_irq = platform_get_irq(pdev, 0); + if (spi_irq < 0) + return spi_irq; + tspi->irq = spi_irq; + ret = request_threaded_irq(tspi->irq, tegra_slink_isr, + tegra_slink_isr_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), tspi); if (ret < 0) { - dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); - goto exit_pm_disable; + dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", + tspi->irq); + goto exit_pm_put; } + tspi->def_command_reg = SLINK_M_S; tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN; tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); - pm_runtime_put(&pdev->dev); - master->dev.of_node = pdev->dev.of_node; - ret = devm_spi_register_master(&pdev->dev, master); + host->dev.of_node = pdev->dev.of_node; + ret = spi_register_controller(host); if (ret < 0) { - dev_err(&pdev->dev, "can not register to master err %d\n", ret); - goto exit_pm_disable; + dev_err(&pdev->dev, "can not register to host err %d\n", ret); + goto exit_free_irq; } + + pm_runtime_put(&pdev->dev); + return ret; +exit_free_irq: + free_irq(spi_irq, tspi); +exit_pm_put: + pm_runtime_put(&pdev->dev); exit_pm_disable: - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra_slink_runtime_suspend(&pdev->dev); + pm_runtime_force_suspend(&pdev->dev); + tegra_slink_deinit_dma_param(tspi, false); exit_rx_dma_free: tegra_slink_deinit_dma_param(tspi, true); -exit_free_irq: - free_irq(spi_irq, tspi); -exit_clk_disable: - clk_disable(tspi->clk); -exit_free_master: - spi_master_put(master); +exit_free_host: + spi_controller_put(host); return ret; } -static int tegra_slink_remove(struct platform_device *pdev) +static void tegra_slink_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct spi_controller *host = spi_controller_get(platform_get_drvdata(pdev)); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); + + spi_unregister_controller(host); free_irq(tspi->irq, tspi); - clk_disable(tspi->clk); + pm_runtime_force_suspend(&pdev->dev); if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); @@ -1171,28 +1146,24 @@ static int tegra_slink_remove(struct platform_device *pdev) if (tspi->rx_dma_chan) tegra_slink_deinit_dma_param(tspi, true); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra_slink_runtime_suspend(&pdev->dev); - - return 0; + spi_controller_put(host); } #ifdef CONFIG_PM_SLEEP static int tegra_slink_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *host = dev_get_drvdata(dev); - return spi_master_suspend(master); + return spi_controller_suspend(host); } static int tegra_slink_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); int ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "pm runtime failed, e = %d\n", ret); return ret; @@ -1201,14 +1172,14 @@ static int tegra_slink_resume(struct device *dev) tegra_slink_writel(tspi, tspi->command2_reg, SLINK_COMMAND2); pm_runtime_put(dev); - return spi_master_resume(master); + return spi_controller_resume(host); } #endif -static int tegra_slink_runtime_suspend(struct device *dev) +static int __maybe_unused tegra_slink_runtime_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); /* Flush all write which are in PPSB queue by reading back */ tegra_slink_readl(tspi, SLINK_MAS_DATA); @@ -1217,10 +1188,10 @@ static int tegra_slink_runtime_suspend(struct device *dev) return 0; } -static int tegra_slink_runtime_resume(struct device *dev) +static int __maybe_unused tegra_slink_runtime_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); - struct tegra_slink_data *tspi = spi_master_get_devdata(master); + struct spi_controller *host = dev_get_drvdata(dev); + struct tegra_slink_data *tspi = spi_controller_get_devdata(host); int ret; ret = clk_prepare_enable(tspi->clk); |
