linux/sound/soc/tegra/tegra20_das.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * tegra20_das.c - Tegra20 DAS driver
   4 *
   5 * Author: Stephen Warren <swarren@nvidia.com>
   6 * Copyright (C) 2010 - NVIDIA, Inc.
   7 */
   8
   9#include <linux/device.h>
  10#include <linux/io.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/regmap.h>
  14#include <linux/slab.h>
  15#include <sound/soc.h>
  16#include "tegra20_das.h"
  17
  18#define DRV_NAME "tegra20-das"
  19
  20static struct tegra20_das *das;
  21
  22static inline void tegra20_das_write(u32 reg, u32 val)
  23{
  24        regmap_write(das->regmap, reg, val);
  25}
  26
  27static inline u32 tegra20_das_read(u32 reg)
  28{
  29        u32 val;
  30
  31        regmap_read(das->regmap, reg, &val);
  32        return val;
  33}
  34
  35int tegra20_das_connect_dap_to_dac(int dap, int dac)
  36{
  37        u32 addr;
  38        u32 reg;
  39
  40        if (!das)
  41                return -ENODEV;
  42
  43        addr = TEGRA20_DAS_DAP_CTRL_SEL +
  44                (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
  45        reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
  46
  47        tegra20_das_write(addr, reg);
  48
  49        return 0;
  50}
  51EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
  52
  53int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
  54                                   int sdata1rx, int sdata2rx)
  55{
  56        u32 addr;
  57        u32 reg;
  58
  59        if (!das)
  60                return -ENODEV;
  61
  62        addr = TEGRA20_DAS_DAP_CTRL_SEL +
  63                (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
  64        reg = (otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P) |
  65                (!!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P) |
  66                (!!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P) |
  67                (!!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P);
  68
  69        tegra20_das_write(addr, reg);
  70
  71        return 0;
  72}
  73EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
  74
  75int tegra20_das_connect_dac_to_dap(int dac, int dap)
  76{
  77        u32 addr;
  78        u32 reg;
  79
  80        if (!das)
  81                return -ENODEV;
  82
  83        addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
  84                (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
  85        reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
  86                dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
  87                dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
  88
  89        tegra20_das_write(addr, reg);
  90
  91        return 0;
  92}
  93EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
  94
  95#define LAST_REG(name) \
  96        (TEGRA20_DAS_##name + \
  97         (TEGRA20_DAS_##name##_STRIDE * (TEGRA20_DAS_##name##_COUNT - 1)))
  98
  99static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg)
 100{
 101        if (reg <= LAST_REG(DAP_CTRL_SEL))
 102                return true;
 103        if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) &&
 104            (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL)))
 105                return true;
 106
 107        return false;
 108}
 109
 110static const struct regmap_config tegra20_das_regmap_config = {
 111        .reg_bits = 32,
 112        .reg_stride = 4,
 113        .val_bits = 32,
 114        .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
 115        .writeable_reg = tegra20_das_wr_rd_reg,
 116        .readable_reg = tegra20_das_wr_rd_reg,
 117        .cache_type = REGCACHE_FLAT,
 118};
 119
 120static int tegra20_das_probe(struct platform_device *pdev)
 121{
 122        void __iomem *regs;
 123        int ret = 0;
 124
 125        if (das)
 126                return -ENODEV;
 127
 128        das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
 129        if (!das) {
 130                ret = -ENOMEM;
 131                goto err;
 132        }
 133        das->dev = &pdev->dev;
 134
 135        regs = devm_platform_ioremap_resource(pdev, 0);
 136        if (IS_ERR(regs)) {
 137                ret = PTR_ERR(regs);
 138                goto err;
 139        }
 140
 141        das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
 142                                            &tegra20_das_regmap_config);
 143        if (IS_ERR(das->regmap)) {
 144                dev_err(&pdev->dev, "regmap init failed\n");
 145                ret = PTR_ERR(das->regmap);
 146                goto err;
 147        }
 148
 149        ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
 150                                             TEGRA20_DAS_DAP_SEL_DAC1);
 151        if (ret) {
 152                dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
 153                goto err;
 154        }
 155        ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
 156                                             TEGRA20_DAS_DAC_SEL_DAP1);
 157        if (ret) {
 158                dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
 159                goto err;
 160        }
 161
 162        ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3,
 163                                             TEGRA20_DAS_DAP_SEL_DAC3);
 164        if (ret) {
 165                dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
 166                goto err;
 167        }
 168        ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_3,
 169                                             TEGRA20_DAS_DAC_SEL_DAP3);
 170        if (ret) {
 171                dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
 172                goto err;
 173        }
 174
 175        platform_set_drvdata(pdev, das);
 176
 177        return 0;
 178
 179err:
 180        das = NULL;
 181        return ret;
 182}
 183
 184static int tegra20_das_remove(struct platform_device *pdev)
 185{
 186        if (!das)
 187                return -ENODEV;
 188
 189        das = NULL;
 190
 191        return 0;
 192}
 193
 194static const struct of_device_id tegra20_das_of_match[] = {
 195        { .compatible = "nvidia,tegra20-das", },
 196        {},
 197};
 198
 199static struct platform_driver tegra20_das_driver = {
 200        .probe = tegra20_das_probe,
 201        .remove = tegra20_das_remove,
 202        .driver = {
 203                .name = DRV_NAME,
 204                .of_match_table = tegra20_das_of_match,
 205        },
 206};
 207module_platform_driver(tegra20_das_driver);
 208
 209MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 210MODULE_DESCRIPTION("Tegra20 DAS driver");
 211MODULE_LICENSE("GPL");
 212MODULE_ALIAS("platform:" DRV_NAME);
 213MODULE_DEVICE_TABLE(of, tegra20_das_of_match);
 214