xref: /linux/drivers/mfd/mcp-sa11x0.c (revision 216f63c41cac9f9f8f181fc19be399293c8c934e)
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>
20d052d1beSRussell King #include <linux/platform_device.h>
21c8602edfSThomas Kunze #include <linux/mfd/mcp.h>
225e742ad6SRussell King 
23dcea83adSRussell King #include <mach/dma.h>
24a09e64fbSRussell King #include <mach/hardware.h>
255e742ad6SRussell King #include <asm/mach-types.h>
265e742ad6SRussell King #include <asm/system.h>
27a09e64fbSRussell King #include <mach/mcp.h>
285e742ad6SRussell King 
29*216f63c4SRussell King #include <mach/assabet.h>
30*216f63c4SRussell King 
315e742ad6SRussell King 
325e742ad6SRussell King struct mcp_sa11x0 {
335e742ad6SRussell King 	u32	mccr0;
345e742ad6SRussell King 	u32	mccr1;
355e742ad6SRussell King };
365e742ad6SRussell King 
375e742ad6SRussell King #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
385e742ad6SRussell King 
395e742ad6SRussell King static void
405e742ad6SRussell King mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
415e742ad6SRussell King {
42*216f63c4SRussell King 	unsigned int mccr0;
435e742ad6SRussell King 
445e742ad6SRussell King 	divisor /= 32;
455e742ad6SRussell King 
46*216f63c4SRussell King 	mccr0 = Ser4MCCR0 & ~0x00007f00;
47*216f63c4SRussell King 	mccr0 |= divisor << 8;
48*216f63c4SRussell King 	Ser4MCCR0 = mccr0;
495e742ad6SRussell King }
505e742ad6SRussell King 
515e742ad6SRussell King static void
525e742ad6SRussell King mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
535e742ad6SRussell King {
54*216f63c4SRussell King 	unsigned int mccr0;
555e742ad6SRussell King 
565e742ad6SRussell King 	divisor /= 32;
575e742ad6SRussell King 
58*216f63c4SRussell King 	mccr0 = Ser4MCCR0 & ~0x0000007f;
59*216f63c4SRussell King 	mccr0 |= divisor;
60*216f63c4SRussell King 	Ser4MCCR0 = mccr0;
615e742ad6SRussell King }
625e742ad6SRussell King 
635e742ad6SRussell King /*
645e742ad6SRussell King  * Write data to the device.  The bit should be set after 3 subframe
655e742ad6SRussell King  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
665e742ad6SRussell King  * We really should try doing something more productive while we
675e742ad6SRussell King  * wait.
685e742ad6SRussell King  */
695e742ad6SRussell King static void
705e742ad6SRussell King mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
715e742ad6SRussell King {
725e742ad6SRussell King 	int ret = -ETIME;
735e742ad6SRussell King 	int i;
745e742ad6SRussell King 
75*216f63c4SRussell King 	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
765e742ad6SRussell King 
775e742ad6SRussell King 	for (i = 0; i < 2; i++) {
785e742ad6SRussell King 		udelay(mcp->rw_timeout);
79*216f63c4SRussell King 		if (Ser4MCSR & MCSR_CWC) {
805e742ad6SRussell King 			ret = 0;
815e742ad6SRussell King 			break;
825e742ad6SRussell King 		}
835e742ad6SRussell King 	}
845e742ad6SRussell King 
855e742ad6SRussell King 	if (ret < 0)
865e742ad6SRussell King 		printk(KERN_WARNING "mcp: write timed out\n");
875e742ad6SRussell King }
885e742ad6SRussell King 
895e742ad6SRussell King /*
905e742ad6SRussell King  * Read data from the device.  The bit should be set after 3 subframe
915e742ad6SRussell King  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
925e742ad6SRussell King  * We really should try doing something more productive while we
935e742ad6SRussell King  * wait.
945e742ad6SRussell King  */
955e742ad6SRussell King static unsigned int
965e742ad6SRussell King mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
975e742ad6SRussell King {
985e742ad6SRussell King 	int ret = -ETIME;
995e742ad6SRussell King 	int i;
1005e742ad6SRussell King 
101*216f63c4SRussell King 	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
1025e742ad6SRussell King 
1035e742ad6SRussell King 	for (i = 0; i < 2; i++) {
1045e742ad6SRussell King 		udelay(mcp->rw_timeout);
105*216f63c4SRussell King 		if (Ser4MCSR & MCSR_CRC) {
106*216f63c4SRussell King 			ret = Ser4MCDR2 & 0xffff;
1075e742ad6SRussell King 			break;
1085e742ad6SRussell King 		}
1095e742ad6SRussell King 	}
1105e742ad6SRussell King 
1115e742ad6SRussell King 	if (ret < 0)
1125e742ad6SRussell King 		printk(KERN_WARNING "mcp: read timed out\n");
1135e742ad6SRussell King 
1145e742ad6SRussell King 	return ret;
1155e742ad6SRussell King }
1165e742ad6SRussell King 
1175e742ad6SRussell King static void mcp_sa11x0_enable(struct mcp *mcp)
1185e742ad6SRussell King {
119*216f63c4SRussell King 	Ser4MCSR = -1;
120*216f63c4SRussell King 	Ser4MCCR0 |= MCCR0_MCE;
1215e742ad6SRussell King }
1225e742ad6SRussell King 
1235e742ad6SRussell King static void mcp_sa11x0_disable(struct mcp *mcp)
1245e742ad6SRussell King {
125*216f63c4SRussell King 	Ser4MCCR0 &= ~MCCR0_MCE;
1265e742ad6SRussell King }
1275e742ad6SRussell King 
1285e742ad6SRussell King /*
1295e742ad6SRussell King  * Our methods.
1305e742ad6SRussell King  */
1315e742ad6SRussell King static struct mcp_ops mcp_sa11x0 = {
1325e742ad6SRussell King 	.set_telecom_divisor	= mcp_sa11x0_set_telecom_divisor,
1335e742ad6SRussell King 	.set_audio_divisor	= mcp_sa11x0_set_audio_divisor,
1345e742ad6SRussell King 	.reg_write		= mcp_sa11x0_write,
1355e742ad6SRussell King 	.reg_read		= mcp_sa11x0_read,
1365e742ad6SRussell King 	.enable			= mcp_sa11x0_enable,
1375e742ad6SRussell King 	.disable		= mcp_sa11x0_disable,
1385e742ad6SRussell King };
1395e742ad6SRussell King 
1403ae5eaecSRussell King static int mcp_sa11x0_probe(struct platform_device *pdev)
1415e742ad6SRussell King {
142323cdfc1SRussell King 	struct mcp_plat_data *data = pdev->dev.platform_data;
1435e742ad6SRussell King 	struct mcp *mcp;
1445e742ad6SRussell King 	int ret;
1455e742ad6SRussell King 
146323cdfc1SRussell King 	if (!data)
1475e742ad6SRussell King 		return -ENODEV;
1485e742ad6SRussell King 
1495dd7bf59SJochen Friedrich 	if (!data->codec)
1505dd7bf59SJochen Friedrich 		return -ENODEV;
1515dd7bf59SJochen Friedrich 
152*216f63c4SRussell King 	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
1535e742ad6SRussell King 		return -EBUSY;
1545e742ad6SRussell King 
1555e742ad6SRussell King 	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
1565e742ad6SRussell King 	if (!mcp) {
1575e742ad6SRussell King 		ret = -ENOMEM;
158*216f63c4SRussell King 		goto release;
1595e742ad6SRussell King 	}
1605e742ad6SRussell King 
1615e742ad6SRussell King 	mcp->owner		= THIS_MODULE;
1625e742ad6SRussell King 	mcp->ops		= &mcp_sa11x0;
163323cdfc1SRussell King 	mcp->sclk_rate		= data->sclk_rate;
164*216f63c4SRussell King 	mcp->dma_audio_rd	= DMA_Ser4MCP0Rd;
165*216f63c4SRussell King 	mcp->dma_audio_wr	= DMA_Ser4MCP0Wr;
166*216f63c4SRussell King 	mcp->dma_telco_rd	= DMA_Ser4MCP1Rd;
167*216f63c4SRussell King 	mcp->dma_telco_wr	= DMA_Ser4MCP1Wr;
1685dd7bf59SJochen Friedrich 	mcp->codec		= data->codec;
1695e742ad6SRussell King 
1703ae5eaecSRussell King 	platform_set_drvdata(pdev, mcp);
1715e742ad6SRussell King 
172*216f63c4SRussell King 	if (machine_is_assabet()) {
173*216f63c4SRussell King 		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
174*216f63c4SRussell King 	}
175*216f63c4SRussell King 
176*216f63c4SRussell King 	/*
177*216f63c4SRussell King 	 * Setup the PPC unit correctly.
178*216f63c4SRussell King 	 */
179*216f63c4SRussell King 	PPDR &= ~PPC_RXD4;
180*216f63c4SRussell King 	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
181*216f63c4SRussell King 	PSDR |= PPC_RXD4;
182*216f63c4SRussell King 	PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
183*216f63c4SRussell King 	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
184*216f63c4SRussell King 
185323cdfc1SRussell King 	/*
186323cdfc1SRussell King 	 * Initialise device.  Note that we initially
187323cdfc1SRussell King 	 * set the sampling rate to minimum.
188323cdfc1SRussell King 	 */
189*216f63c4SRussell King 	Ser4MCSR = -1;
190*216f63c4SRussell King 	Ser4MCCR1 = data->mccr1;
191*216f63c4SRussell King 	Ser4MCCR0 = data->mccr0 | 0x7f7f;
1925e742ad6SRussell King 
1935e742ad6SRussell King 	/*
1945e742ad6SRussell King 	 * Calculate the read/write timeout (us) from the bit clock
1955e742ad6SRussell King 	 * rate.  This is the period for 3 64-bit frames.  Always
1965e742ad6SRussell King 	 * round this time up.
1975e742ad6SRussell King 	 */
1985e742ad6SRussell King 	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
1995e742ad6SRussell King 			  mcp->sclk_rate;
2005e742ad6SRussell King 
2015dd7bf59SJochen Friedrich 	ret = mcp_host_register(mcp, data->codec_pdata);
2025e742ad6SRussell King 	if (ret == 0)
2035e742ad6SRussell King 		goto out;
2045e742ad6SRussell King 
2055e742ad6SRussell King  release:
206*216f63c4SRussell King 	release_mem_region(0x80060000, 0x60);
2073ae5eaecSRussell King 	platform_set_drvdata(pdev, NULL);
2085e742ad6SRussell King 
2095e742ad6SRussell King  out:
2105e742ad6SRussell King 	return ret;
2115e742ad6SRussell King }
2125e742ad6SRussell King 
213*216f63c4SRussell King static int mcp_sa11x0_remove(struct platform_device *dev)
2145e742ad6SRussell King {
215*216f63c4SRussell King 	struct mcp *mcp = platform_get_drvdata(dev);
2165e742ad6SRussell King 
217*216f63c4SRussell King 	platform_set_drvdata(dev, NULL);
2185e742ad6SRussell King 	mcp_host_unregister(mcp);
219*216f63c4SRussell King 	release_mem_region(0x80060000, 0x60);
2205e742ad6SRussell King 
2215e742ad6SRussell King 	return 0;
2225e742ad6SRussell King }
2235e742ad6SRussell King 
2243ae5eaecSRussell King static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
2255e742ad6SRussell King {
2263ae5eaecSRussell King 	struct mcp *mcp = platform_get_drvdata(dev);
2275e742ad6SRussell King 
228*216f63c4SRussell King 	priv(mcp)->mccr0 = Ser4MCCR0;
229*216f63c4SRussell King 	priv(mcp)->mccr1 = Ser4MCCR1;
230*216f63c4SRussell King 	Ser4MCCR0 &= ~MCCR0_MCE;
2319480e307SRussell King 
2325e742ad6SRussell King 	return 0;
2335e742ad6SRussell King }
2345e742ad6SRussell King 
2353ae5eaecSRussell King static int mcp_sa11x0_resume(struct platform_device *dev)
2365e742ad6SRussell King {
2373ae5eaecSRussell King 	struct mcp *mcp = platform_get_drvdata(dev);
2385e742ad6SRussell King 
239*216f63c4SRussell King 	Ser4MCCR1 = priv(mcp)->mccr1;
240*216f63c4SRussell King 	Ser4MCCR0 = priv(mcp)->mccr0;
2419480e307SRussell King 
2425e742ad6SRussell King 	return 0;
2435e742ad6SRussell King }
2445e742ad6SRussell King 
2455e742ad6SRussell King /*
2465e742ad6SRussell King  * The driver for the SA11x0 MCP port.
2475e742ad6SRussell King  */
2484f46d6e7SKay Sievers MODULE_ALIAS("platform:sa11x0-mcp");
2494f46d6e7SKay Sievers 
2503ae5eaecSRussell King static struct platform_driver mcp_sa11x0_driver = {
2515e742ad6SRussell King 	.probe		= mcp_sa11x0_probe,
2525e742ad6SRussell King 	.remove		= mcp_sa11x0_remove,
2535e742ad6SRussell King 	.suspend	= mcp_sa11x0_suspend,
2545e742ad6SRussell King 	.resume		= mcp_sa11x0_resume,
2553ae5eaecSRussell King 	.driver		= {
2563ae5eaecSRussell King 		.name	= "sa11x0-mcp",
2573ae5eaecSRussell King 	},
2585e742ad6SRussell King };
2595e742ad6SRussell King 
2605e742ad6SRussell King /*
2615e742ad6SRussell King  * This needs re-working
2625e742ad6SRussell King  */
26365349d60SMark Brown module_platform_driver(mcp_sa11x0_driver);
2645e742ad6SRussell King 
2655e742ad6SRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
2665e742ad6SRussell King MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
2675e742ad6SRussell King MODULE_LICENSE("GPL");
268