diff options
Diffstat (limited to 'drivers/soc/tegra/fuse/fuse-tegra20.c')
| -rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra20.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 294413a969a0..fdecf7b7c246 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014, 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/>. - * * Based on drivers/misc/eeprom/sunxi_sid.c */ @@ -25,8 +14,9 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/kobject.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/random.h> #include <soc/tegra/fuse.h> @@ -57,9 +47,13 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) u32 value = 0; int err; + err = pm_runtime_resume_and_get(fuse->dev); + if (err) + return err; + mutex_lock(&fuse->apbdma.lock); - fuse->apbdma.config.src_addr = fuse->apbdma.phys + FUSE_BEGIN + offset; + fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset; err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config); if (err) @@ -77,8 +71,6 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) reinit_completion(&fuse->apbdma.wait); - clk_prepare_enable(fuse->clk); - dmaengine_submit(dma_desc); dma_async_issue_pending(fuse->apbdma.chan); time_left = wait_for_completion_timeout(&fuse->apbdma.wait, @@ -89,36 +81,71 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) else value = *fuse->apbdma.virt; - clk_disable_unprepare(fuse->clk); - out: mutex_unlock(&fuse->apbdma.lock); + pm_runtime_put(fuse->dev); return value; } +static bool dma_filter(struct dma_chan *chan, void *filter_param) +{ + struct device_node *np = chan->device->dev->of_node; + + return of_device_is_compatible(np, "nvidia,tegra20-apbdma"); +} + +static void tegra20_fuse_release_channel(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_release_channel(fuse->apbdma.chan); + fuse->apbdma.chan = NULL; +} + +static void tegra20_fuse_free_coherent(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_free_coherent(fuse->dev, sizeof(u32), fuse->apbdma.virt, + fuse->apbdma.phys); + fuse->apbdma.virt = NULL; + fuse->apbdma.phys = 0x0; +} + static int tegra20_fuse_probe(struct tegra_fuse *fuse) { dma_cap_mask_t mask; + int err; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - fuse->apbdma.chan = dma_request_channel(mask, NULL, NULL); + fuse->apbdma.chan = dma_request_channel(mask, dma_filter, NULL); if (!fuse->apbdma.chan) return -EPROBE_DEFER; + err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_release_channel, + fuse); + if (err) + return err; + fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32), &fuse->apbdma.phys, GFP_KERNEL); - if (!fuse->apbdma.virt) { - dma_release_channel(fuse->apbdma.chan); + if (!fuse->apbdma.virt) return -ENOMEM; - } + + err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_free_coherent, + fuse); + if (err) + return err; fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; fuse->apbdma.config.src_maxburst = 1; fuse->apbdma.config.dst_maxburst = 1; + fuse->apbdma.config.direction = DMA_DEV_TO_MEM; + fuse->apbdma.config.device_fc = false; init_completion(&fuse->apbdma.wait); mutex_init(&fuse->apbdma.lock); @@ -166,4 +193,6 @@ const struct tegra_fuse_soc tegra20_fuse_soc = { .speedo_init = tegra20_init_speedo_data, .probe = tegra20_fuse_probe, .info = &tegra20_fuse_info, + .soc_attr_group = &tegra_soc_attr_group, + .clk_suspend_on = false, }; |
