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 struct resource *res; 124 void __iomem *regs; 125 int ret = 0; 126 127 if (das) 128 return -ENODEV; 129 130 das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL); 131 if (!das) { 132 ret = -ENOMEM; 133 goto err; 134 } 135 das->dev = &pdev->dev; 136 137 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 138 regs = devm_ioremap_resource(&pdev->dev, res); 139 if (IS_ERR(regs)) { 140 ret = PTR_ERR(regs); 141 goto err; 142 } 143 144 das->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 145 &tegra20_das_regmap_config); 146 if (IS_ERR(das->regmap)) { 147 dev_err(&pdev->dev, "regmap init failed\n"); 148 ret = PTR_ERR(das->regmap); 149 goto err; 150 } 151 152 ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1, 153 TEGRA20_DAS_DAP_SEL_DAC1); 154 if (ret) { 155 dev_err(&pdev->dev, "Can't set up DAS DAP connection\n"); 156 goto err; 157 } 158 ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1, 159 TEGRA20_DAS_DAC_SEL_DAP1); 160 if (ret) { 161 dev_err(&pdev->dev, "Can't set up DAS DAC connection\n"); 162 goto err; 163 } 164 165 ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3, 166 TEGRA20_DAS_DAP_SEL_DAC3); 167 if (ret) { 168 dev_err(&pdev->dev, "Can't set up DAS DAP connection\n"); 169 goto err; 170 } 171 ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_3, 172 TEGRA20_DAS_DAC_SEL_DAP3); 173 if (ret) { 174 dev_err(&pdev->dev, "Can't set up DAS DAC connection\n"); 175 goto err; 176 } 177 178 platform_set_drvdata(pdev, das); 179 180 return 0; 181 182 err: 183 das = NULL; 184 return ret; 185 } 186 187 static int tegra20_das_remove(struct platform_device *pdev) 188 { 189 if (!das) 190 return -ENODEV; 191 192 das = NULL; 193 194 return 0; 195 } 196 197 static const struct of_device_id tegra20_das_of_match[] = { 198 { .compatible = "nvidia,tegra20-das", }, 199 {}, 200 }; 201 202 static struct platform_driver tegra20_das_driver = { 203 .probe = tegra20_das_probe, 204 .remove = tegra20_das_remove, 205 .driver = { 206 .name = DRV_NAME, 207 .of_match_table = tegra20_das_of_match, 208 }, 209 }; 210 module_platform_driver(tegra20_das_driver); 211 212 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 213 MODULE_DESCRIPTION("Tegra20 DAS driver"); 214 MODULE_LICENSE("GPL"); 215 MODULE_ALIAS("platform:" DRV_NAME); 216 MODULE_DEVICE_TABLE(of, tegra20_das_of_match); 217