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 20 static struct tegra20_das *das; 21 22 static inline void tegra20_das_write(u32 reg, u32 val) 23 { 24 regmap_write(das->regmap, reg, val); 25 } 26 27 static inline u32 tegra20_das_read(u32 reg) 28 { 29 u32 val; 30 31 regmap_read(das->regmap, reg, &val); 32 return val; 33 } 34 35 int 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 } 51 EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac); 52 53 int 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 } 73 EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap); 74 75 int 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 } 93 EXPORT_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 99 static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg) 100 { 101 if ((reg >= TEGRA20_DAS_DAP_CTRL_SEL) && 102 (reg <= LAST_REG(DAP_CTRL_SEL))) 103 return true; 104 if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) && 105 (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL))) 106 return true; 107 108 return false; 109 } 110 111 static const struct regmap_config tegra20_das_regmap_config = { 112 .reg_bits = 32, 113 .reg_stride = 4, 114 .val_bits = 32, 115 .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL), 116 .writeable_reg = tegra20_das_wr_rd_reg, 117 .readable_reg = tegra20_das_wr_rd_reg, 118 .cache_type = REGCACHE_FLAT, 119 }; 120 121 static int tegra20_das_probe(struct platform_device *pdev) 122 { 123 void __iomem *regs; 124 int ret = 0; 125 126 if (das) 127 return -ENODEV; 128 129 das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL); 130 if (!das) { 131 ret = -ENOMEM; 132 goto err; 133 } 134 das->dev = &pdev->dev; 135 136 regs = devm_platform_ioremap_resource(pdev, 0); 137 if (IS_ERR(regs)) { 138 ret = PTR_ERR(regs); 139 goto err; 140 } 141 142 das->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 143 &tegra20_das_regmap_config); 144 if (IS_ERR(das->regmap)) { 145 dev_err(&pdev->dev, "regmap init failed\n"); 146 ret = PTR_ERR(das->regmap); 147 goto err; 148 } 149 150 ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1, 151 TEGRA20_DAS_DAP_SEL_DAC1); 152 if (ret) { 153 dev_err(&pdev->dev, "Can't set up DAS DAP connection\n"); 154 goto err; 155 } 156 ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1, 157 TEGRA20_DAS_DAC_SEL_DAP1); 158 if (ret) { 159 dev_err(&pdev->dev, "Can't set up DAS DAC connection\n"); 160 goto err; 161 } 162 163 ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3, 164 TEGRA20_DAS_DAP_SEL_DAC3); 165 if (ret) { 166 dev_err(&pdev->dev, "Can't set up DAS DAP connection\n"); 167 goto err; 168 } 169 ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_3, 170 TEGRA20_DAS_DAC_SEL_DAP3); 171 if (ret) { 172 dev_err(&pdev->dev, "Can't set up DAS DAC connection\n"); 173 goto err; 174 } 175 176 platform_set_drvdata(pdev, das); 177 178 return 0; 179 180 err: 181 das = NULL; 182 return ret; 183 } 184 185 static int tegra20_das_remove(struct platform_device *pdev) 186 { 187 if (!das) 188 return -ENODEV; 189 190 das = NULL; 191 192 return 0; 193 } 194 195 static const struct of_device_id tegra20_das_of_match[] = { 196 { .compatible = "nvidia,tegra20-das", }, 197 {}, 198 }; 199 200 static struct platform_driver tegra20_das_driver = { 201 .probe = tegra20_das_probe, 202 .remove = tegra20_das_remove, 203 .driver = { 204 .name = DRV_NAME, 205 .of_match_table = tegra20_das_of_match, 206 }, 207 }; 208 module_platform_driver(tegra20_das_driver); 209 210 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 211 MODULE_DESCRIPTION("Tegra20 DAS driver"); 212 MODULE_LICENSE("GPL"); 213 MODULE_ALIAS("platform:" DRV_NAME); 214 MODULE_DEVICE_TABLE(of, tegra20_das_of_match); 215