1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Copyright 2012 Freescale Semiconductor, Inc. 4 // Copyright 2012 Linaro Ltd. 5 // Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 6 // 7 // Initial development of this code was funded by 8 // Phytec Messtechnik GmbH, https://www.phytec.de 9 10 #include <linux/clk.h> 11 #include <linux/debugfs.h> 12 #include <linux/err.h> 13 #include <linux/io.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_device.h> 17 #include <linux/platform_device.h> 18 #include <linux/slab.h> 19 20 #include "imx-audmux.h" 21 22 #define DRIVER_NAME "imx-audmux" 23 24 static struct clk *audmux_clk; 25 static void __iomem *audmux_base; 26 static u32 *regcache; 27 static u32 reg_max; 28 29 #define IMX_AUDMUX_V2_PTCR(x) ((x) * 8) 30 #define IMX_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) 31 32 #ifdef CONFIG_DEBUG_FS 33 static struct dentry *audmux_debugfs_root; 34 35 /* There is an annoying discontinuity in the SSI numbering with regard 36 * to the Linux number of the devices */ 37 static const char *audmux_port_string(int port) 38 { 39 switch (port) { 40 case MX31_AUDMUX_PORT1_SSI0: 41 return "imx-ssi.0"; 42 case MX31_AUDMUX_PORT2_SSI1: 43 return "imx-ssi.1"; 44 case MX31_AUDMUX_PORT3_SSI_PINS_3: 45 return "SSI3"; 46 case MX31_AUDMUX_PORT4_SSI_PINS_4: 47 return "SSI4"; 48 case MX31_AUDMUX_PORT5_SSI_PINS_5: 49 return "SSI5"; 50 case MX31_AUDMUX_PORT6_SSI_PINS_6: 51 return "SSI6"; 52 default: 53 return "UNKNOWN"; 54 } 55 } 56 57 static ssize_t audmux_read_file(struct file *file, char __user *user_buf, 58 size_t count, loff_t *ppos) 59 { 60 ssize_t ret; 61 char *buf; 62 uintptr_t port = (uintptr_t)file->private_data; 63 u32 pdcr, ptcr; 64 65 ret = clk_prepare_enable(audmux_clk); 66 if (ret) 67 return ret; 68 69 ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); 70 pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); 71 72 clk_disable_unprepare(audmux_clk); 73 74 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 75 if (!buf) 76 return -ENOMEM; 77 78 ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", 79 pdcr, ptcr); 80 81 if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) 82 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 83 "TxFS output from %s, ", 84 audmux_port_string((ptcr >> 27) & 0x7)); 85 else 86 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 87 "TxFS input, "); 88 89 if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR) 90 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 91 "TxClk output from %s", 92 audmux_port_string((ptcr >> 22) & 0x7)); 93 else 94 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 95 "TxClk input"); 96 97 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); 98 99 if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) { 100 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 101 "Port is symmetric"); 102 } else { 103 if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR) 104 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 105 "RxFS output from %s, ", 106 audmux_port_string((ptcr >> 17) & 0x7)); 107 else 108 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 109 "RxFS input, "); 110 111 if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR) 112 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 113 "RxClk output from %s", 114 audmux_port_string((ptcr >> 12) & 0x7)); 115 else 116 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 117 "RxClk input"); 118 } 119 120 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 121 "\nData received from %s\n", 122 audmux_port_string((pdcr >> 13) & 0x7)); 123 124 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 125 126 kfree(buf); 127 128 return ret; 129 } 130 131 static const struct file_operations audmux_debugfs_fops = { 132 .open = simple_open, 133 .read = audmux_read_file, 134 .llseek = default_llseek, 135 }; 136 137 static void audmux_debugfs_init(void) 138 { 139 uintptr_t i; 140 char buf[20]; 141 142 audmux_debugfs_root = debugfs_create_dir("audmux", NULL); 143 144 for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { 145 snprintf(buf, sizeof(buf), "ssi%lu", i); 146 debugfs_create_file(buf, 0444, audmux_debugfs_root, 147 (void *)i, &audmux_debugfs_fops); 148 } 149 } 150 151 static void audmux_debugfs_remove(void) 152 { 153 debugfs_remove_recursive(audmux_debugfs_root); 154 } 155 #else 156 static inline void audmux_debugfs_init(void) 157 { 158 } 159 160 static inline void audmux_debugfs_remove(void) 161 { 162 } 163 #endif 164 165 static enum imx_audmux_type { 166 IMX21_AUDMUX, 167 IMX31_AUDMUX, 168 } audmux_type; 169 170 static const struct of_device_id imx_audmux_dt_ids[] = { 171 { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, }, 172 { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, }, 173 { /* sentinel */ } 174 }; 175 MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids); 176 177 static const uint8_t port_mapping[] = { 178 0x0, 0x4, 0x8, 0x10, 0x14, 0x1c, 179 }; 180 181 int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr) 182 { 183 if (audmux_type != IMX21_AUDMUX) 184 return -EINVAL; 185 186 if (!audmux_base) 187 return -ENOSYS; 188 189 if (port >= ARRAY_SIZE(port_mapping)) 190 return -EINVAL; 191 192 writel(pcr, audmux_base + port_mapping[port]); 193 194 return 0; 195 } 196 EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port); 197 198 int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, 199 unsigned int pdcr) 200 { 201 int ret; 202 203 if (audmux_type != IMX31_AUDMUX) 204 return -EINVAL; 205 206 if (!audmux_base) 207 return -ENOSYS; 208 209 ret = clk_prepare_enable(audmux_clk); 210 if (ret) 211 return ret; 212 213 writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); 214 writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); 215 216 clk_disable_unprepare(audmux_clk); 217 218 return 0; 219 } 220 EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); 221 222 static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, 223 struct device_node *of_node) 224 { 225 struct device_node *child; 226 227 for_each_available_child_of_node(of_node, child) { 228 unsigned int port; 229 unsigned int ptcr = 0; 230 unsigned int pdcr = 0; 231 unsigned int pcr = 0; 232 unsigned int val; 233 int ret; 234 int i = 0; 235 236 ret = of_property_read_u32(child, "fsl,audmux-port", &port); 237 if (ret) { 238 dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%pOF\"\n", 239 child); 240 continue; 241 } 242 if (!of_property_read_bool(child, "fsl,port-config")) { 243 dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n", 244 child); 245 continue; 246 } 247 248 for (i = 0; (ret = of_property_read_u32_index(child, 249 "fsl,port-config", i, &val)) == 0; 250 ++i) { 251 if (audmux_type == IMX31_AUDMUX) { 252 if (i % 2) 253 pdcr |= val; 254 else 255 ptcr |= val; 256 } else { 257 pcr |= val; 258 } 259 } 260 261 if (ret != -EOVERFLOW) { 262 dev_err(&pdev->dev, "Failed to read u32 at index %d of child %pOF\n", 263 i, child); 264 continue; 265 } 266 267 if (audmux_type == IMX31_AUDMUX) { 268 if (i % 2) { 269 dev_err(&pdev->dev, "One pdcr value is missing in child node %pOF\n", 270 child); 271 continue; 272 } 273 imx_audmux_v2_configure_port(port, ptcr, pdcr); 274 } else { 275 imx_audmux_v1_configure_port(port, pcr); 276 } 277 } 278 279 return 0; 280 } 281 282 static int imx_audmux_probe(struct platform_device *pdev) 283 { 284 audmux_base = devm_platform_ioremap_resource(pdev, 0); 285 if (IS_ERR(audmux_base)) 286 return PTR_ERR(audmux_base); 287 288 audmux_clk = devm_clk_get(&pdev->dev, "audmux"); 289 if (IS_ERR(audmux_clk)) { 290 dev_dbg(&pdev->dev, "cannot get clock: %ld\n", 291 PTR_ERR(audmux_clk)); 292 audmux_clk = NULL; 293 } 294 295 audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); 296 297 switch (audmux_type) { 298 case IMX31_AUDMUX: 299 audmux_debugfs_init(); 300 reg_max = 14; 301 break; 302 case IMX21_AUDMUX: 303 reg_max = 6; 304 break; 305 default: 306 dev_err(&pdev->dev, "unsupported version!\n"); 307 return -EINVAL; 308 } 309 310 regcache = devm_kzalloc(&pdev->dev, sizeof(u32) * reg_max, GFP_KERNEL); 311 if (!regcache) 312 return -ENOMEM; 313 314 imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); 315 316 return 0; 317 } 318 319 static int imx_audmux_remove(struct platform_device *pdev) 320 { 321 if (audmux_type == IMX31_AUDMUX) 322 audmux_debugfs_remove(); 323 324 return 0; 325 } 326 327 #ifdef CONFIG_PM_SLEEP 328 static int imx_audmux_suspend(struct device *dev) 329 { 330 int i; 331 332 clk_prepare_enable(audmux_clk); 333 334 for (i = 0; i < reg_max; i++) 335 regcache[i] = readl(audmux_base + i * 4); 336 337 clk_disable_unprepare(audmux_clk); 338 339 return 0; 340 } 341 342 static int imx_audmux_resume(struct device *dev) 343 { 344 int i; 345 346 clk_prepare_enable(audmux_clk); 347 348 for (i = 0; i < reg_max; i++) 349 writel(regcache[i], audmux_base + i * 4); 350 351 clk_disable_unprepare(audmux_clk); 352 353 return 0; 354 } 355 #endif /* CONFIG_PM_SLEEP */ 356 357 static const struct dev_pm_ops imx_audmux_pm = { 358 SET_SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) 359 }; 360 361 static struct platform_driver imx_audmux_driver = { 362 .probe = imx_audmux_probe, 363 .remove = imx_audmux_remove, 364 .driver = { 365 .name = DRIVER_NAME, 366 .pm = &imx_audmux_pm, 367 .of_match_table = imx_audmux_dt_ids, 368 } 369 }; 370 371 static int __init imx_audmux_init(void) 372 { 373 return platform_driver_register(&imx_audmux_driver); 374 } 375 subsys_initcall(imx_audmux_init); 376 377 static void __exit imx_audmux_exit(void) 378 { 379 platform_driver_unregister(&imx_audmux_driver); 380 } 381 module_exit(imx_audmux_exit); 382 383 MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver"); 384 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 385 MODULE_LICENSE("GPL v2"); 386 MODULE_ALIAS("platform:" DRIVER_NAME); 387