Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tegra20_das.c - Tegra20 DAS driver
0004  *
0005  * Author: Stephen Warren <swarren@nvidia.com>
0006  * Copyright (C) 2010 - NVIDIA, Inc.
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/io.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/regmap.h>
0014 #include <linux/slab.h>
0015 #include <sound/soc.h>
0016 
0017 #define DRV_NAME "tegra20-das"
0018 
0019 /* Register TEGRA20_DAS_DAP_CTRL_SEL */
0020 #define TEGRA20_DAS_DAP_CTRL_SEL            0x00
0021 #define TEGRA20_DAS_DAP_CTRL_SEL_COUNT          5
0022 #define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE         4
0023 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P       31
0024 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S       1
0025 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30
0026 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1
0027 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29
0028 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1
0029 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P     0
0030 #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S     5
0031 
0032 /* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
0033 #define TEGRA20_DAS_DAP_SEL_DAC1    0
0034 #define TEGRA20_DAS_DAP_SEL_DAC2    1
0035 #define TEGRA20_DAS_DAP_SEL_DAC3    2
0036 #define TEGRA20_DAS_DAP_SEL_DAP1    16
0037 #define TEGRA20_DAS_DAP_SEL_DAP2    17
0038 #define TEGRA20_DAS_DAP_SEL_DAP3    18
0039 #define TEGRA20_DAS_DAP_SEL_DAP4    19
0040 #define TEGRA20_DAS_DAP_SEL_DAP5    20
0041 
0042 /* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
0043 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL          0x40
0044 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT        3
0045 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE       4
0046 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28
0047 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4
0048 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24
0049 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4
0050 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P    0
0051 #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S    4
0052 
0053 /*
0054  * Values for:
0055  * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
0056  * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
0057  * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
0058  */
0059 #define TEGRA20_DAS_DAC_SEL_DAP1    0
0060 #define TEGRA20_DAS_DAC_SEL_DAP2    1
0061 #define TEGRA20_DAS_DAC_SEL_DAP3    2
0062 #define TEGRA20_DAS_DAC_SEL_DAP4    3
0063 #define TEGRA20_DAS_DAC_SEL_DAP5    4
0064 
0065 /*
0066  * Names/IDs of the DACs/DAPs.
0067  */
0068 
0069 #define TEGRA20_DAS_DAP_ID_1 0
0070 #define TEGRA20_DAS_DAP_ID_2 1
0071 #define TEGRA20_DAS_DAP_ID_3 2
0072 #define TEGRA20_DAS_DAP_ID_4 3
0073 #define TEGRA20_DAS_DAP_ID_5 4
0074 
0075 #define TEGRA20_DAS_DAC_ID_1 0
0076 #define TEGRA20_DAS_DAC_ID_2 1
0077 #define TEGRA20_DAS_DAC_ID_3 2
0078 
0079 struct tegra20_das {
0080     struct regmap *regmap;
0081 };
0082 
0083 /*
0084  * Terminology:
0085  * DAS: Digital audio switch (HW module controlled by this driver)
0086  * DAP: Digital audio port (port/pins on Tegra device)
0087  * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
0088  *
0089  * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
0090  * DAC, or another DAP. When DAPs are connected, one must be the master and
0091  * one the slave. Each DAC allows selection of a specific DAP for input, to
0092  * cater for the case where N DAPs are connected to 1 DAC for broadcast
0093  * output.
0094  *
0095  * This driver is dumb; no attempt is made to ensure that a valid routing
0096  * configuration is programmed.
0097  */
0098 
0099 static inline void tegra20_das_write(struct tegra20_das *das, u32 reg, u32 val)
0100 {
0101     regmap_write(das->regmap, reg, val);
0102 }
0103 
0104 static void tegra20_das_connect_dap_to_dac(struct tegra20_das *das, int dap, int dac)
0105 {
0106     u32 addr;
0107     u32 reg;
0108 
0109     addr = TEGRA20_DAS_DAP_CTRL_SEL +
0110         (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
0111     reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
0112 
0113     tegra20_das_write(das, addr, reg);
0114 }
0115 
0116 static void tegra20_das_connect_dac_to_dap(struct tegra20_das *das, int dac, int dap)
0117 {
0118     u32 addr;
0119     u32 reg;
0120 
0121     addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
0122         (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
0123     reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
0124         dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
0125         dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
0126 
0127     tegra20_das_write(das, addr, reg);
0128 }
0129 
0130 #define LAST_REG(name) \
0131     (TEGRA20_DAS_##name + \
0132      (TEGRA20_DAS_##name##_STRIDE * (TEGRA20_DAS_##name##_COUNT - 1)))
0133 
0134 static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg)
0135 {
0136     if (reg <= LAST_REG(DAP_CTRL_SEL))
0137         return true;
0138     if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) &&
0139         (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL)))
0140         return true;
0141 
0142     return false;
0143 }
0144 
0145 static const struct regmap_config tegra20_das_regmap_config = {
0146     .reg_bits = 32,
0147     .reg_stride = 4,
0148     .val_bits = 32,
0149     .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
0150     .writeable_reg = tegra20_das_wr_rd_reg,
0151     .readable_reg = tegra20_das_wr_rd_reg,
0152     .cache_type = REGCACHE_FLAT,
0153 };
0154 
0155 static int tegra20_das_probe(struct platform_device *pdev)
0156 {
0157     void __iomem *regs;
0158     struct tegra20_das *das;
0159 
0160     das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
0161     if (!das)
0162         return -ENOMEM;
0163 
0164     regs = devm_platform_ioremap_resource(pdev, 0);
0165     if (IS_ERR(regs))
0166         return PTR_ERR(regs);
0167 
0168     das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
0169                         &tegra20_das_regmap_config);
0170     if (IS_ERR(das->regmap)) {
0171         dev_err(&pdev->dev, "regmap init failed\n");
0172         return PTR_ERR(das->regmap);
0173     }
0174 
0175     tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1,
0176                        TEGRA20_DAS_DAP_SEL_DAC1);
0177     tegra20_das_connect_dac_to_dap(das, TEGRA20_DAS_DAC_ID_1,
0178                        TEGRA20_DAS_DAC_SEL_DAP1);
0179     tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_3,
0180                        TEGRA20_DAS_DAP_SEL_DAC3);
0181     tegra20_das_connect_dac_to_dap(das, TEGRA20_DAS_DAC_ID_3,
0182                        TEGRA20_DAS_DAC_SEL_DAP3);
0183 
0184     return 0;
0185 }
0186 
0187 static const struct of_device_id tegra20_das_of_match[] = {
0188     { .compatible = "nvidia,tegra20-das", },
0189     {},
0190 };
0191 
0192 static struct platform_driver tegra20_das_driver = {
0193     .probe = tegra20_das_probe,
0194     .driver = {
0195         .name = DRV_NAME,
0196         .of_match_table = tegra20_das_of_match,
0197     },
0198 };
0199 module_platform_driver(tegra20_das_driver);
0200 
0201 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
0202 MODULE_DESCRIPTION("Tegra20 DAS driver");
0203 MODULE_LICENSE("GPL");
0204 MODULE_ALIAS("platform:" DRV_NAME);
0205 MODULE_DEVICE_TABLE(of, tegra20_das_of_match);