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 = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); 79 80 if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) 81 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 82 "TxFS output from %s, ", 83 audmux_port_string((ptcr >> 27) & 0x7)); 84 else 85 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 86 "TxFS input, "); 87 88 if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR) 89 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 90 "TxClk output from %s", 91 audmux_port_string((ptcr >> 22) & 0x7)); 92 else 93 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 94 "TxClk input"); 95 96 ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); 97 98 if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) { 99 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 100 "Port is symmetric"); 101 } else { 102 if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR) 103 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 104 "RxFS output from %s, ", 105 audmux_port_string((ptcr >> 17) & 0x7)); 106 else 107 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 108 "RxFS input, "); 109 110 if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR) 111 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 112 "RxClk output from %s", 113 audmux_port_string((ptcr >> 12) & 0x7)); 114 else 115 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 116 "RxClk input"); 117 } 118 119 ret += scnprintf(buf + ret, PAGE_SIZE - ret, 120 "\nData received from %s\n", 121 audmux_port_string((pdcr >> 13) & 0x7)); 122 123 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 124 125 kfree(buf); 126 127 return ret; 128 } 129 130 static const struct file_operations audmux_debugfs_fops = { 131 .open = simple_open, 132 .read = audmux_read_file, 133 .llseek = default_llseek, 134 }; 135 136 static void audmux_debugfs_init(void) 137 { 138 uintptr_t i; 139 char buf[20]; 140 141 audmux_debugfs_root = debugfs_create_dir("audmux", NULL); 142 143 for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { 144 snprintf(buf, sizeof(buf), "ssi%lu", i); 145 debugfs_create_file(buf, 0444, audmux_debugfs_root, 146 (void *)i, &audmux_debugfs_fops); 147 } 148 } 149 150 static void audmux_debugfs_remove(void) 151 { 152 debugfs_remove_recursive(audmux_debugfs_root); 153 } 154 #else 155 static inline void audmux_debugfs_init(void) 156 { 157 } 158 159 static inline void audmux_debugfs_remove(void) 160 { 161 } 162 #endif 163 164 static enum imx_audmux_type { 165 IMX21_AUDMUX, 166 IMX31_AUDMUX, 167 } audmux_type; 168 169 static const struct of_device_id imx_audmux_dt_ids[] = { 170 { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, }, 171 { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, }, 172 { /* sentinel */ } 173 }; 174 MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids); 175 176 static const uint8_t port_mapping[] = { 177 0x0, 0x4, 0x8, 0x10, 0x14, 0x1c, 178 }; 179 180 int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr) 181 { 182 if (audmux_type != IMX21_AUDMUX) 183 return -EINVAL; 184 185 if (!audmux_base) 186 return -ENOSYS; 187 188 if (port >= ARRAY_SIZE(port_mapping)) 189 return -EINVAL; 190 191 writel(pcr, audmux_base + port_mapping[port]); 192 193 return 0; 194 } 195 EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port); 196 197 int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, 198 unsigned int pdcr) 199 { 200 int ret; 201 202 if (audmux_type != IMX31_AUDMUX) 203 return -EINVAL; 204 205 if (!audmux_base) 206 return -ENOSYS; 207 208 ret = clk_prepare_enable(audmux_clk); 209 if (ret) 210 return ret; 211 212 writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); 213 writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); 214 215 clk_disable_unprepare(audmux_clk); 216 217 return 0; 218 } 219 EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port); 220 221 static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, 222 struct device_node *of_node) 223 { 224 struct device_node *child; 225 226 for_each_available_child_of_node(of_node, child) { 227 unsigned int port; 228 unsigned int ptcr = 0; 229 unsigned int pdcr = 0; 230 unsigned int pcr = 0; 231 unsigned int val; 232 int ret; 233 int i = 0; 234 235 ret = of_property_read_u32(child, "fsl,audmux-port", &port); 236 if (ret) { 237 dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%pOF\"\n", 238 child); 239 continue; 240 } 241 if (!of_property_read_bool(child, "fsl,port-config")) { 242 dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n", 243 child); 244 continue; 245 } 246 247 for (i = 0; (ret = of_property_read_u32_index(child, 248 "fsl,port-config", i, &val)) == 0; 249 ++i) { 250 if (audmux_type == IMX31_AUDMUX) { 251 if (i % 2) 252 pdcr |= val; 253 else 254 ptcr |= val; 255 } else { 256 pcr |= val; 257 } 258 } 259 260 if (ret != -EOVERFLOW) { 261 dev_err(&pdev->dev, "Failed to read u32 at index %d of child %pOF\n", 262 i, child); 263 continue; 264 } 265 266 if (audmux_type == IMX31_AUDMUX) { 267 if (i % 2) { 268 dev_err(&pdev->dev, "One pdcr value is missing in child node %pOF\n", 269 child); 270 continue; 271 } 272 imx_audmux_v2_configure_port(port, ptcr, pdcr); 273 } else { 274 imx_audmux_v1_configure_port(port, pcr); 275 } 276 } 277 278 return 0; 279 } 280 281 static int imx_audmux_probe(struct platform_device *pdev) 282 { 283 audmux_base = devm_platform_ioremap_resource(pdev, 0); 284 if (IS_ERR(audmux_base)) 285 return PTR_ERR(audmux_base); 286 287 audmux_clk = devm_clk_get(&pdev->dev, "audmux"); 288 if (IS_ERR(audmux_clk)) { 289 dev_dbg(&pdev->dev, "cannot get clock: %ld\n", 290 PTR_ERR(audmux_clk)); 291 audmux_clk = NULL; 292 } 293 294 audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); 295 296 switch (audmux_type) { 297 case IMX31_AUDMUX: 298 audmux_debugfs_init(); 299 reg_max = 14; 300 break; 301 case IMX21_AUDMUX: 302 reg_max = 6; 303 break; 304 default: 305 dev_err(&pdev->dev, "unsupported version!\n"); 306 return -EINVAL; 307 } 308 309 regcache = devm_kzalloc(&pdev->dev, sizeof(u32) * reg_max, GFP_KERNEL); 310 if (!regcache) 311 return -ENOMEM; 312 313 imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); 314 315 return 0; 316 } 317 318 static int imx_audmux_remove(struct platform_device *pdev) 319 { 320 if (audmux_type == IMX31_AUDMUX) 321 audmux_debugfs_remove(); 322 323 return 0; 324 } 325 326 #ifdef CONFIG_PM_SLEEP 327 static int imx_audmux_suspend(struct device *dev) 328 { 329 int i; 330 331 clk_prepare_enable(audmux_clk); 332 333 for (i = 0; i < reg_max; i++) 334 regcache[i] = readl(audmux_base + i * 4); 335 336 clk_disable_unprepare(audmux_clk); 337 338 return 0; 339 } 340 341 static int imx_audmux_resume(struct device *dev) 342 { 343 int i; 344 345 clk_prepare_enable(audmux_clk); 346 347 for (i = 0; i < reg_max; i++) 348 writel(regcache[i], audmux_base + i * 4); 349 350 clk_disable_unprepare(audmux_clk); 351 352 return 0; 353 } 354 #endif /* CONFIG_PM_SLEEP */ 355 356 static const struct dev_pm_ops imx_audmux_pm = { 357 SET_SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) 358 }; 359 360 static struct platform_driver imx_audmux_driver = { 361 .probe = imx_audmux_probe, 362 .remove = imx_audmux_remove, 363 .driver = { 364 .name = DRIVER_NAME, 365 .pm = &imx_audmux_pm, 366 .of_match_table = imx_audmux_dt_ids, 367 } 368 }; 369 370 static int __init imx_audmux_init(void) 371 { 372 return platform_driver_register(&imx_audmux_driver); 373 } 374 subsys_initcall(imx_audmux_init); 375 376 static void __exit imx_audmux_exit(void) 377 { 378 platform_driver_unregister(&imx_audmux_driver); 379 } 380 module_exit(imx_audmux_exit); 381 382 MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver"); 383 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 384 MODULE_LICENSE("GPL v2"); 385 MODULE_ALIAS("platform:" DRIVER_NAME); 386