mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 12:14:01 +08:00
34800598b2
These are all specific to some driver. They are typically the platform side of a change in the drivers directory, such as adding a new driver or extending the interface to the platform. In cases where there is no maintainer for the driver, or the maintainer prefers to have the platform changes in the same branch as the driver changes, the patches to the drivers are included as well. A much smaller set of driver updates that depend on other branches getting merged first will be sent later. The new export of tegra_chip_uid conflicts with other changes in fuse.c. In rtc-sa1100.c, the global removal of IRQF_DISABLED conflicts with the cleanup of the interrupt handling of that driver. Signed-off-by: Arnd Bergmann <arnd@arndb.de> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIVAwUAT24/Y2CrR//JCVInAQLUdw//V4pKPuKempSe1kuD2MJfqldHwEVOlAUt of1IhLPAp8tpCscPDQ0yTy3ixquINg4jVnaDLL+E0quVbhLu6hlS2TYNKDEaVAAc cPUtVEUdja7Cfu4+bXX2vcWM/UyI6Ax7bsUUcwu4wFnEsjA6qOSu/jYY4jXDguHq ODGQSaSz0XQkfVBsWOlO8W/ejb0T3y+Ro3M/Vz5qJsMnZBR8R/i9aUYDFGiZ1GTn 3APHB7ALz6SS5/9SJS65PH16poBexcea5gyb3gnR1yt30kRmMTOAWrLC+JdyqFaO 7LHXW514+D1QbWV2gwNCWhQSLbgp9PWq/FXJtq4StW7tgNbDbj1d1Dc1GX+fvk2M bBih1yWoIVx6CZWFBQ7gsbqVHUZ/sW2fo76yb8K5dVPXx0fL5lEkv5Xwk3gxbqt5 lPE8+z+jiL5D+8RK1DZQu1PfxzaMwDZkJkVoGLCcdyM7FvnX3LIYf2bqbcp+zrQL lz9aht9C1k12R7feOX8emlluNd3eaKv/6jLrOasUP5wrJDam5hesSD5mLeTlAdxZ U8XJe4L24dFv15/yrMCzcyes5EmB3aS3nfb9TsSfq22IOKo2PCQLCnL6Z/rfM+1p mGu7BqdBnx3/8NkHdUrttMWjuPNh77MfPM6RO/E+TaBLHtwvKoLWJAHAYQNmt2xH IbGcyorBD5s= =pQ3X -----END PGP SIGNATURE----- Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull "ARM: driver specific updates" from Arnd Bergmann: "These are all specific to some driver. They are typically the platform side of a change in the drivers directory, such as adding a new driver or extending the interface to the platform. In cases where there is no maintainer for the driver, or the maintainer prefers to have the platform changes in the same branch as the driver changes, the patches to the drivers are included as well. A much smaller set of driver updates that depend on other branches getting merged first will be sent later. The new export of tegra_chip_uid conflicts with other changes in fuse.c. In rtc-sa1100.c, the global removal of IRQF_DISABLED conflicts with the cleanup of the interrupt handling of that driver. Signed-off-by: Arnd Bergmann <arnd@arndb.de>" Fixed up aforementioned trivial conflicts. * tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (94 commits) ARM: SAMSUNG: change the name from s3c-sdhci to exynos4-sdhci mmc: sdhci-s3c: add platform data for the second capability ARM: SAMSUNG: support the second capability for samsung-soc ARM: EXYNOS: add support DMA for EXYNOS4X12 SoC ARM: EXYNOS: Add apb_pclk clkdev entry for mdma1 ARM: EXYNOS: Enable MDMA driver regulator: Remove bq24022 regulator driver rtc: sa1100: add OF support pxa: magician/hx4700: Convert to gpio-regulator from bq24022 ARM: OMAP3+: SmartReflex: fix error handling ARM: OMAP3+: SmartReflex: fix the use of debugfs_create_* API ARM: OMAP3+: SmartReflex: micro-optimization for sanity check ARM: OMAP3+: SmartReflex: misc cleanups ARM: OMAP3+: SmartReflex: move late_initcall() closer to its argument ARM: OMAP3+: SmartReflex: add missing platform_set_drvdata() ARM: OMAP3+: hwmod: add SmartReflex IRQs ARM: OMAP3+: SmartReflex: clear ERRCONFIG_VPBOUNDINTST only on a need ARM: OMAP3+: SmartReflex: Fix status masking in ERRCONFIG register ARM: OMAP3+: SmartReflex: Add a shutdown hook ARM: OMAP3+: SmartReflex Class3: disable errorgen before disable VP ... Conflicts: arch/arm/mach-tegra/Makefile arch/arm/mach-tegra/fuse.c drivers/rtc/rtc-sa1100.c
315 lines
7.5 KiB
C
315 lines
7.5 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/err.h>
|
|
#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>
|
|
|
|
#include "imx-audmux.h"
|
|
|
|
#define DRIVER_NAME "imx-audmux"
|
|
|
|
static struct clk *audmux_clk;
|
|
static void __iomem *audmux_base;
|
|
|
|
#define IMX_AUDMUX_V2_PTCR(x) ((x) * 8)
|
|
#define IMX_AUDMUX_V2_PDCR(x) ((x) * 8 + 4)
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
static struct dentry *audmux_debugfs_root;
|
|
|
|
static int audmux_open_file(struct inode *inode, struct file *file)
|
|
{
|
|
file->private_data = inode->i_private;
|
|
return 0;
|
|
}
|
|
|
|
/* There is an annoying discontinuity in the SSI numbering with regard
|
|
* to the Linux number of the devices */
|
|
static const char *audmux_port_string(int port)
|
|
{
|
|
switch (port) {
|
|
case MX31_AUDMUX_PORT1_SSI0:
|
|
return "imx-ssi.0";
|
|
case MX31_AUDMUX_PORT2_SSI1:
|
|
return "imx-ssi.1";
|
|
case MX31_AUDMUX_PORT3_SSI_PINS_3:
|
|
return "SSI3";
|
|
case MX31_AUDMUX_PORT4_SSI_PINS_4:
|
|
return "SSI4";
|
|
case MX31_AUDMUX_PORT5_SSI_PINS_5:
|
|
return "SSI5";
|
|
case MX31_AUDMUX_PORT6_SSI_PINS_6:
|
|
return "SSI6";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
ssize_t ret;
|
|
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
|
int port = (int)file->private_data;
|
|
u32 pdcr, ptcr;
|
|
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
if (audmux_clk)
|
|
clk_prepare_enable(audmux_clk);
|
|
|
|
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);
|
|
|
|
ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
|
|
pdcr, ptcr);
|
|
|
|
if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"TxFS output from %s, ",
|
|
audmux_port_string((ptcr >> 27) & 0x7));
|
|
else
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"TxFS input, ");
|
|
|
|
if (ptcr & IMX_AUDMUX_V2_PTCR_TCLKDIR)
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"TxClk output from %s",
|
|
audmux_port_string((ptcr >> 22) & 0x7));
|
|
else
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"TxClk input");
|
|
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
|
|
|
|
if (ptcr & IMX_AUDMUX_V2_PTCR_SYN) {
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"Port is symmetric");
|
|
} else {
|
|
if (ptcr & IMX_AUDMUX_V2_PTCR_RFSDIR)
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"RxFS output from %s, ",
|
|
audmux_port_string((ptcr >> 17) & 0x7));
|
|
else
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"RxFS input, ");
|
|
|
|
if (ptcr & IMX_AUDMUX_V2_PTCR_RCLKDIR)
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"RxClk output from %s",
|
|
audmux_port_string((ptcr >> 12) & 0x7));
|
|
else
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"RxClk input");
|
|
}
|
|
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
"\nData received from %s\n",
|
|
audmux_port_string((pdcr >> 13) & 0x7));
|
|
|
|
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
|
|
|
kfree(buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations audmux_debugfs_fops = {
|
|
.open = audmux_open_file,
|
|
.read = audmux_read_file,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static void __init audmux_debugfs_init(void)
|
|
{
|
|
int i;
|
|
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 = 1; i < 8; i++) {
|
|
snprintf(buf, sizeof(buf), "ssi%d", i);
|
|
if (!debugfs_create_file(buf, 0444, audmux_debugfs_root,
|
|
(void *)i, &audmux_debugfs_fops))
|
|
pr_warning("Failed to create AUDMUX port %d debugfs file\n",
|
|
i);
|
|
}
|
|
}
|
|
|
|
static void __devexit audmux_debugfs_remove(void)
|
|
{
|
|
debugfs_remove_recursive(audmux_debugfs_root);
|
|
}
|
|
#else
|
|
static inline void audmux_debugfs_init(void)
|
|
{
|
|
}
|
|
|
|
static inline void audmux_debugfs_remove(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
enum imx_audmux_type {
|
|
IMX21_AUDMUX,
|
|
IMX31_AUDMUX,
|
|
} audmux_type;
|
|
|
|
static 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], },
|
|
{ /* sentinel */ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids);
|
|
|
|
static const uint8_t port_mapping[] = {
|
|
0x0, 0x4, 0x8, 0x10, 0x14, 0x1c,
|
|
};
|
|
|
|
int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr)
|
|
{
|
|
if (audmux_type != IMX21_AUDMUX)
|
|
return -EINVAL;
|
|
|
|
if (!audmux_base)
|
|
return -ENOSYS;
|
|
|
|
if (port >= ARRAY_SIZE(port_mapping))
|
|
return -EINVAL;
|
|
|
|
writel(pcr, audmux_base + port_mapping[port]);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port);
|
|
|
|
int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
|
|
unsigned int pdcr)
|
|
{
|
|
if (audmux_type != IMX31_AUDMUX)
|
|
return -EINVAL;
|
|
|
|
if (!audmux_base)
|
|
return -ENOSYS;
|
|
|
|
if (audmux_clk)
|
|
clk_prepare_enable(audmux_clk);
|
|
|
|
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);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
|
|
|
|
static int __devinit 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_request_and_ioremap(&pdev->dev, res);
|
|
if (!audmux_base)
|
|
return -EADDRNOTAVAIL;
|
|
|
|
audmux_clk = clk_get(&pdev->dev, "audmux");
|
|
if (IS_ERR(audmux_clk)) {
|
|
dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
|
|
PTR_ERR(audmux_clk));
|
|
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_debugfs_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __devexit imx_audmux_remove(struct platform_device *pdev)
|
|
{
|
|
if (audmux_type == IMX31_AUDMUX)
|
|
audmux_debugfs_remove();
|
|
clk_put(audmux_clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver imx_audmux_driver = {
|
|
.probe = imx_audmux_probe,
|
|
.remove = __devexit_p(imx_audmux_remove),
|
|
.id_table = imx_audmux_ids,
|
|
.driver = {
|
|
.name = DRIVER_NAME,
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = imx_audmux_dt_ids,
|
|
}
|
|
};
|
|
|
|
static int __init imx_audmux_init(void)
|
|
{
|
|
return platform_driver_register(&imx_audmux_driver);
|
|
}
|
|
subsys_initcall(imx_audmux_init);
|
|
|
|
static void __exit imx_audmux_exit(void)
|
|
{
|
|
platform_driver_unregister(&imx_audmux_driver);
|
|
}
|
|
module_exit(imx_audmux_exit);
|
|
|
|
MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver");
|
|
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_ALIAS("platform:" DRIVER_NAME);
|