diff options
Diffstat (limited to 'sound/soc/fsl/imx-audmux.c')
| -rw-r--r-- | sound/soc/fsl/imx-audmux.c | 186 |
1 files changed, 94 insertions, 92 deletions
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index fc57da341d61..f8335a04595a 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -1,21 +1,11 @@ -/* - * Copyright 2012 Freescale Semiconductor, Inc. - * Copyright 2012 Linaro Ltd. - * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * Initial development of this code was funded by - * Phytec Messtechnik GmbH, http://www.phytec.de - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2012 Freescale Semiconductor, Inc. +// Copyright 2012 Linaro Ltd. +// Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> +// +// Initial development of this code was funded by +// Phytec Messtechnik GmbH, https://www.phytec.de #include <linux/clk.h> #include <linux/debugfs.h> @@ -23,7 +13,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -33,6 +22,8 @@ static struct clk *audmux_clk; static void __iomem *audmux_base; +static u32 *regcache; +static u32 reg_max; #define IMX_AUDMUX_V2_PTCR(x) ((x) * 8) #define IMX_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) @@ -70,65 +61,61 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, uintptr_t port = (uintptr_t)file->private_data; u32 pdcr, ptcr; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", - pdcr, ptcr); + ret = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "TxFS output from %s, ", audmux_port_string((ptcr >> 27) & 0x7)); else - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "TxFS input, "); if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "TxClk output from %s", audmux_port_string((ptcr >> 22) & 0x7)); else - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "TxClk input"); - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) { - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "Port is symmetric"); } else { if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "RxFS output from %s, ", audmux_port_string((ptcr >> 17) & 0x7)); else - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "RxFS input, "); if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "RxClk output from %s", audmux_port_string((ptcr >> 12) & 0x7)); else - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "RxClk input"); } - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\nData received from %s\n", audmux_port_string((pdcr >> 13) & 0x7)); @@ -151,17 +138,11 @@ static void audmux_debugfs_init(void) char buf[20]; audmux_debugfs_root = debugfs_create_dir("audmux", NULL); - if (!audmux_debugfs_root) { - pr_warning("Failed to create AUDMUX debugfs root\n"); - return; - } for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { snprintf(buf, sizeof(buf), "ssi%lu", i); - if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, - (void *)i, &audmux_debugfs_fops)) - pr_warning("Failed to create AUDMUX port %lu debugfs file\n", - i); + debugfs_create_file(buf, 0444, audmux_debugfs_root, + (void *)i, &audmux_debugfs_fops); } } @@ -184,22 +165,9 @@ static enum imx_audmux_type { IMX31_AUDMUX, } audmux_type; -static const struct platform_device_id imx_audmux_ids[] = { - { - .name = "imx21-audmux", - .driver_data = IMX21_AUDMUX, - }, { - .name = "imx31-audmux", - .driver_data = IMX31_AUDMUX, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, imx_audmux_ids); - static const struct of_device_id imx_audmux_dt_ids[] = { - { .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], }, - { .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], }, + { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, }, + { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids); @@ -236,17 +204,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, if (!audmux_base) return -ENOSYS; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); return 0; } @@ -268,13 +233,13 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, ret = of_property_read_u32(child, "fsl,audmux-port", &port); if (ret) { - dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n", - child->full_name); + dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%pOF\"\n", + child); continue; } - if (!of_property_read_bool(child, "fsl,port-config")) { - dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n", - child->full_name); + if (!of_property_present(child, "fsl,port-config")) { + dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n", + child); continue; } @@ -292,15 +257,15 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, } if (ret != -EOVERFLOW) { - dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n", - i, child->full_name); + dev_err(&pdev->dev, "Failed to read u32 at index %d of child %pOF\n", + i, child); continue; } if (audmux_type == IMX31_AUDMUX) { if (i % 2) { - dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n", - child->full_name); + dev_err(&pdev->dev, "One pdcr value is missing in child node %pOF\n", + child); continue; } imx_audmux_v2_configure_port(port, ptcr, pdcr); @@ -314,12 +279,7 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev, static int imx_audmux_probe(struct platform_device *pdev) { - struct resource *res; - const struct of_device_id *of_id = - of_match_device(imx_audmux_dt_ids, &pdev->dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - audmux_base = devm_ioremap_resource(&pdev->dev, res); + audmux_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(audmux_base)) return PTR_ERR(audmux_base); @@ -330,32 +290,74 @@ static int imx_audmux_probe(struct platform_device *pdev) audmux_clk = NULL; } - if (of_id) - pdev->id_entry = of_id->data; - audmux_type = pdev->id_entry->driver_data; - if (audmux_type == IMX31_AUDMUX) + audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); + + switch (audmux_type) { + case IMX31_AUDMUX: audmux_debugfs_init(); + reg_max = 14; + break; + case IMX21_AUDMUX: + reg_max = 6; + break; + default: + dev_err(&pdev->dev, "unsupported version!\n"); + return -EINVAL; + } - if (of_id) - imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); + regcache = devm_kcalloc(&pdev->dev, reg_max, sizeof(u32), GFP_KERNEL); + if (!regcache) + return -ENOMEM; + + imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node); return 0; } -static int imx_audmux_remove(struct platform_device *pdev) +static void imx_audmux_remove(struct platform_device *pdev) { if (audmux_type == IMX31_AUDMUX) audmux_debugfs_remove(); +} + +static int imx_audmux_suspend(struct device *dev) +{ + int i; + + clk_prepare_enable(audmux_clk); + + for (i = 0; i < reg_max; i++) + regcache[i] = readl(audmux_base + i * 4); + + clk_disable_unprepare(audmux_clk); return 0; } +static int imx_audmux_resume(struct device *dev) +{ + int i; + + clk_prepare_enable(audmux_clk); + + for (i = 0; i < reg_max; i++) + writel(regcache[i], audmux_base + i * 4); + + clk_disable_unprepare(audmux_clk); + + return 0; +} + +static const struct dev_pm_ops imx_audmux_pm = { + SYSTEM_SLEEP_PM_OPS(imx_audmux_suspend, imx_audmux_resume) +}; + static struct platform_driver imx_audmux_driver = { .probe = imx_audmux_probe, .remove = imx_audmux_remove, - .id_table = imx_audmux_ids, .driver = { .name = DRIVER_NAME, + .pm = pm_sleep_ptr(&imx_audmux_pm), .of_match_table = imx_audmux_dt_ids, } }; |
