xref: /linux/drivers/mfd/mcp-sa11x0.c (revision 9480e307cd88ef09ec9294c7d97ebec18e6d2221)
15e742ad6SRussell King /*
25e742ad6SRussell King  *  linux/drivers/mfd/mcp-sa11x0.c
35e742ad6SRussell King  *
45e742ad6SRussell King  *  Copyright (C) 2001-2005 Russell King
55e742ad6SRussell King  *
65e742ad6SRussell King  * This program is free software; you can redistribute it and/or modify
75e742ad6SRussell King  * it under the terms of the GNU General Public License as published by
85e742ad6SRussell King  * the Free Software Foundation; either version 2 of the License.
95e742ad6SRussell King  *
105e742ad6SRussell King  *  SA11x0 MCP (Multimedia Communications Port) driver.
115e742ad6SRussell King  *
125e742ad6SRussell King  *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
135e742ad6SRussell King  */
145e742ad6SRussell King #include <linux/module.h>
155e742ad6SRussell King #include <linux/init.h>
165e742ad6SRussell King #include <linux/errno.h>
175e742ad6SRussell King #include <linux/kernel.h>
185e742ad6SRussell King #include <linux/delay.h>
195e742ad6SRussell King #include <linux/spinlock.h>
205e742ad6SRussell King #include <linux/slab.h>
215e742ad6SRussell King #include <linux/device.h>
225e742ad6SRussell King 
235e742ad6SRussell King #include <asm/dma.h>
245e742ad6SRussell King #include <asm/hardware.h>
255e742ad6SRussell King #include <asm/mach-types.h>
265e742ad6SRussell King #include <asm/system.h>
27323cdfc1SRussell King #include <asm/arch/mcp.h>
285e742ad6SRussell King 
295e742ad6SRussell King #include <asm/arch/assabet.h>
305e742ad6SRussell King 
315e742ad6SRussell King #include "mcp.h"
325e742ad6SRussell King 
335e742ad6SRussell King struct mcp_sa11x0 {
345e742ad6SRussell King 	u32	mccr0;
355e742ad6SRussell King 	u32	mccr1;
365e742ad6SRussell King };
375e742ad6SRussell King 
385e742ad6SRussell King #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
395e742ad6SRussell King 
405e742ad6SRussell King static void
415e742ad6SRussell King mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
425e742ad6SRussell King {
435e742ad6SRussell King 	unsigned int mccr0;
445e742ad6SRussell King 
455e742ad6SRussell King 	divisor /= 32;
465e742ad6SRussell King 
475e742ad6SRussell King 	mccr0 = Ser4MCCR0 & ~0x00007f00;
485e742ad6SRussell King 	mccr0 |= divisor << 8;
495e742ad6SRussell King 	Ser4MCCR0 = mccr0;
505e742ad6SRussell King }
515e742ad6SRussell King 
525e742ad6SRussell King static void
535e742ad6SRussell King mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
545e742ad6SRussell King {
555e742ad6SRussell King 	unsigned int mccr0;
565e742ad6SRussell King 
575e742ad6SRussell King 	divisor /= 32;
585e742ad6SRussell King 
595e742ad6SRussell King 	mccr0 = Ser4MCCR0 & ~0x0000007f;
605e742ad6SRussell King 	mccr0 |= divisor;
615e742ad6SRussell King 	Ser4MCCR0 = mccr0;
625e742ad6SRussell King }
635e742ad6SRussell King 
645e742ad6SRussell King /*
655e742ad6SRussell King  * Write data to the device.  The bit should be set after 3 subframe
665e742ad6SRussell King  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
675e742ad6SRussell King  * We really should try doing something more productive while we
685e742ad6SRussell King  * wait.
695e742ad6SRussell King  */
705e742ad6SRussell King static void
715e742ad6SRussell King mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
725e742ad6SRussell King {
735e742ad6SRussell King 	int ret = -ETIME;
745e742ad6SRussell King 	int i;
755e742ad6SRussell King 
765e742ad6SRussell King 	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
775e742ad6SRussell King 
785e742ad6SRussell King 	for (i = 0; i < 2; i++) {
795e742ad6SRussell King 		udelay(mcp->rw_timeout);
805e742ad6SRussell King 		if (Ser4MCSR & MCSR_CWC) {
815e742ad6SRussell King 			ret = 0;
825e742ad6SRussell King 			break;
835e742ad6SRussell King 		}
845e742ad6SRussell King 	}
855e742ad6SRussell King 
865e742ad6SRussell King 	if (ret < 0)
875e742ad6SRussell King 		printk(KERN_WARNING "mcp: write timed out\n");
885e742ad6SRussell King }
895e742ad6SRussell King 
905e742ad6SRussell King /*
915e742ad6SRussell King  * Read data from the device.  The bit should be set after 3 subframe
925e742ad6SRussell King  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
935e742ad6SRussell King  * We really should try doing something more productive while we
945e742ad6SRussell King  * wait.
955e742ad6SRussell King  */
965e742ad6SRussell King static unsigned int
975e742ad6SRussell King mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
985e742ad6SRussell King {
995e742ad6SRussell King 	int ret = -ETIME;
1005e742ad6SRussell King 	int i;
1015e742ad6SRussell King 
1025e742ad6SRussell King 	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
1035e742ad6SRussell King 
1045e742ad6SRussell King 	for (i = 0; i < 2; i++) {
1055e742ad6SRussell King 		udelay(mcp->rw_timeout);
1065e742ad6SRussell King 		if (Ser4MCSR & MCSR_CRC) {
1075e742ad6SRussell King 			ret = Ser4MCDR2 & 0xffff;
1085e742ad6SRussell King 			break;
1095e742ad6SRussell King 		}
1105e742ad6SRussell King 	}
1115e742ad6SRussell King 
1125e742ad6SRussell King 	if (ret < 0)
1135e742ad6SRussell King 		printk(KERN_WARNING "mcp: read timed out\n");
1145e742ad6SRussell King 
1155e742ad6SRussell King 	return ret;
1165e742ad6SRussell King }
1175e742ad6SRussell King 
1185e742ad6SRussell King static void mcp_sa11x0_enable(struct mcp *mcp)
1195e742ad6SRussell King {
1205e742ad6SRussell King 	Ser4MCSR = -1;
1215e742ad6SRussell King 	Ser4MCCR0 |= MCCR0_MCE;
1225e742ad6SRussell King }
1235e742ad6SRussell King 
1245e742ad6SRussell King static void mcp_sa11x0_disable(struct mcp *mcp)
1255e742ad6SRussell King {
1265e742ad6SRussell King 	Ser4MCCR0 &= ~MCCR0_MCE;
1275e742ad6SRussell King }
1285e742ad6SRussell King 
1295e742ad6SRussell King /*
1305e742ad6SRussell King  * Our methods.
1315e742ad6SRussell King  */
1325e742ad6SRussell King static struct mcp_ops mcp_sa11x0 = {
1335e742ad6SRussell King 	.set_telecom_divisor	= mcp_sa11x0_set_telecom_divisor,
1345e742ad6SRussell King 	.set_audio_divisor	= mcp_sa11x0_set_audio_divisor,
1355e742ad6SRussell King 	.reg_write		= mcp_sa11x0_write,
1365e742ad6SRussell King 	.reg_read		= mcp_sa11x0_read,
1375e742ad6SRussell King 	.enable			= mcp_sa11x0_enable,
1385e742ad6SRussell King 	.disable		= mcp_sa11x0_disable,
1395e742ad6SRussell King };
1405e742ad6SRussell King 
1415e742ad6SRussell King static int mcp_sa11x0_probe(struct device *dev)
1425e742ad6SRussell King {
1435e742ad6SRussell King 	struct platform_device *pdev = to_platform_device(dev);
144323cdfc1SRussell King 	struct mcp_plat_data *data = pdev->dev.platform_data;
1455e742ad6SRussell King 	struct mcp *mcp;
1465e742ad6SRussell King 	int ret;
1475e742ad6SRussell King 
148323cdfc1SRussell King 	if (!data)
1495e742ad6SRussell King 		return -ENODEV;
1505e742ad6SRussell King 
1515e742ad6SRussell King 	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
1525e742ad6SRussell King 		return -EBUSY;
1535e742ad6SRussell King 
1545e742ad6SRussell King 	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
1555e742ad6SRussell King 	if (!mcp) {
1565e742ad6SRussell King 		ret = -ENOMEM;
1575e742ad6SRussell King 		goto release;
1585e742ad6SRussell King 	}
1595e742ad6SRussell King 
1605e742ad6SRussell King 	mcp->owner		= THIS_MODULE;
1615e742ad6SRussell King 	mcp->ops		= &mcp_sa11x0;
162323cdfc1SRussell King 	mcp->sclk_rate		= data->sclk_rate;
1635e742ad6SRussell King 	mcp->dma_audio_rd	= DMA_Ser4MCP0Rd;
1645e742ad6SRussell King 	mcp->dma_audio_wr	= DMA_Ser4MCP0Wr;
1655e742ad6SRussell King 	mcp->dma_telco_rd	= DMA_Ser4MCP1Rd;
1665e742ad6SRussell King 	mcp->dma_telco_wr	= DMA_Ser4MCP1Wr;
1675e742ad6SRussell King 
1685e742ad6SRussell King 	dev_set_drvdata(dev, mcp);
1695e742ad6SRussell King 
1705e742ad6SRussell King 	if (machine_is_assabet()) {
1715e742ad6SRussell King 		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
1725e742ad6SRussell King 	}
1735e742ad6SRussell King 
1745e742ad6SRussell King 	/*
1755e742ad6SRussell King 	 * Setup the PPC unit correctly.
1765e742ad6SRussell King 	 */
1775e742ad6SRussell King 	PPDR &= ~PPC_RXD4;
1785e742ad6SRussell King 	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
1795e742ad6SRussell King 	PSDR |= PPC_RXD4;
1805e742ad6SRussell King 	PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
1815e742ad6SRussell King 	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
1825e742ad6SRussell King 
183323cdfc1SRussell King 	/*
184323cdfc1SRussell King 	 * Initialise device.  Note that we initially
185323cdfc1SRussell King 	 * set the sampling rate to minimum.
186323cdfc1SRussell King 	 */
1875e742ad6SRussell King 	Ser4MCSR = -1;
188323cdfc1SRussell King 	Ser4MCCR1 = data->mccr1;
189323cdfc1SRussell King 	Ser4MCCR0 = data->mccr0 | 0x7f7f;
1905e742ad6SRussell King 
1915e742ad6SRussell King 	/*
1925e742ad6SRussell King 	 * Calculate the read/write timeout (us) from the bit clock
1935e742ad6SRussell King 	 * rate.  This is the period for 3 64-bit frames.  Always
1945e742ad6SRussell King 	 * round this time up.
1955e742ad6SRussell King 	 */
1965e742ad6SRussell King 	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
1975e742ad6SRussell King 			  mcp->sclk_rate;
1985e742ad6SRussell King 
1995e742ad6SRussell King 	ret = mcp_host_register(mcp);
2005e742ad6SRussell King 	if (ret == 0)
2015e742ad6SRussell King 		goto out;
2025e742ad6SRussell King 
2035e742ad6SRussell King  release:
2045e742ad6SRussell King 	release_mem_region(0x80060000, 0x60);
2055e742ad6SRussell King 	dev_set_drvdata(dev, NULL);
2065e742ad6SRussell King 
2075e742ad6SRussell King  out:
2085e742ad6SRussell King 	return ret;
2095e742ad6SRussell King }
2105e742ad6SRussell King 
2115e742ad6SRussell King static int mcp_sa11x0_remove(struct device *dev)
2125e742ad6SRussell King {
2135e742ad6SRussell King 	struct mcp *mcp = dev_get_drvdata(dev);
2145e742ad6SRussell King 
2155e742ad6SRussell King 	dev_set_drvdata(dev, NULL);
2165e742ad6SRussell King 	mcp_host_unregister(mcp);
2175e742ad6SRussell King 	release_mem_region(0x80060000, 0x60);
2185e742ad6SRussell King 
2195e742ad6SRussell King 	return 0;
2205e742ad6SRussell King }
2215e742ad6SRussell King 
222*9480e307SRussell King static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state)
2235e742ad6SRussell King {
2245e742ad6SRussell King 	struct mcp *mcp = dev_get_drvdata(dev);
2255e742ad6SRussell King 
2265e742ad6SRussell King 	priv(mcp)->mccr0 = Ser4MCCR0;
2275e742ad6SRussell King 	priv(mcp)->mccr1 = Ser4MCCR1;
2285e742ad6SRussell King 	Ser4MCCR0 &= ~MCCR0_MCE;
229*9480e307SRussell King 
2305e742ad6SRussell King 	return 0;
2315e742ad6SRussell King }
2325e742ad6SRussell King 
233*9480e307SRussell King static int mcp_sa11x0_resume(struct device *dev)
2345e742ad6SRussell King {
2355e742ad6SRussell King 	struct mcp *mcp = dev_get_drvdata(dev);
2365e742ad6SRussell King 
2375e742ad6SRussell King 	Ser4MCCR1 = priv(mcp)->mccr1;
2385e742ad6SRussell King 	Ser4MCCR0 = priv(mcp)->mccr0;
239*9480e307SRussell King 
2405e742ad6SRussell King 	return 0;
2415e742ad6SRussell King }
2425e742ad6SRussell King 
2435e742ad6SRussell King /*
2445e742ad6SRussell King  * The driver for the SA11x0 MCP port.
2455e742ad6SRussell King  */
2465e742ad6SRussell King static struct device_driver mcp_sa11x0_driver = {
2475e742ad6SRussell King 	.name		= "sa11x0-mcp",
2485e742ad6SRussell King 	.bus		= &platform_bus_type,
2495e742ad6SRussell King 	.probe		= mcp_sa11x0_probe,
2505e742ad6SRussell King 	.remove		= mcp_sa11x0_remove,
2515e742ad6SRussell King 	.suspend	= mcp_sa11x0_suspend,
2525e742ad6SRussell King 	.resume		= mcp_sa11x0_resume,
2535e742ad6SRussell King };
2545e742ad6SRussell King 
2555e742ad6SRussell King /*
2565e742ad6SRussell King  * This needs re-working
2575e742ad6SRussell King  */
2585e742ad6SRussell King static int __init mcp_sa11x0_init(void)
2595e742ad6SRussell King {
2605e742ad6SRussell King 	return driver_register(&mcp_sa11x0_driver);
2615e742ad6SRussell King }
2625e742ad6SRussell King 
2635e742ad6SRussell King static void __exit mcp_sa11x0_exit(void)
2645e742ad6SRussell King {
2655e742ad6SRussell King 	driver_unregister(&mcp_sa11x0_driver);
2665e742ad6SRussell King }
2675e742ad6SRussell King 
2685e742ad6SRussell King module_init(mcp_sa11x0_init);
2695e742ad6SRussell King module_exit(mcp_sa11x0_exit);
2705e742ad6SRussell King 
2715e742ad6SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
2725e742ad6SRussell King MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
2735e742ad6SRussell King MODULE_LICENSE("GPL");
274