2 * linux/drivers/mfd/mcp-sa11x0.c
4 * Copyright (C) 2001-2005 Russell King
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License.
10 * SA11x0 MCP (Multimedia Communications Port) driver.
12 * MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/errno.h>
17 #include <linux/kernel.h>
18 #include <linux/delay.h>
19 #include <linux/spinlock.h>
20 #include <linux/slab.h>
21 #include <linux/platform_device.h>
22 #include <linux/mfd/mcp.h>
25 #include <mach/hardware.h>
26 #include <asm/mach-types.h>
27 #include <asm/system.h>
30 #include <mach/assabet.h>
38 #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
41 mcp_sa11x0_set_telecom_divisor(struct mcp
*mcp
, unsigned int divisor
)
47 mccr0
= Ser4MCCR0
& ~0x00007f00;
48 mccr0
|= divisor
<< 8;
53 mcp_sa11x0_set_audio_divisor(struct mcp
*mcp
, unsigned int divisor
)
59 mccr0
= Ser4MCCR0
& ~0x0000007f;
65 * Write data to the device. The bit should be set after 3 subframe
66 * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
67 * We really should try doing something more productive while we
71 mcp_sa11x0_write(struct mcp
*mcp
, unsigned int reg
, unsigned int val
)
76 Ser4MCDR2
= reg
<< 17 | MCDR2_Wr
| (val
& 0xffff);
78 for (i
= 0; i
< 2; i
++) {
79 udelay(mcp
->rw_timeout
);
80 if (Ser4MCSR
& MCSR_CWC
) {
87 printk(KERN_WARNING
"mcp: write timed out\n");
91 * Read data from the device. The bit should be set after 3 subframe
92 * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
93 * We really should try doing something more productive while we
97 mcp_sa11x0_read(struct mcp
*mcp
, unsigned int reg
)
102 Ser4MCDR2
= reg
<< 17 | MCDR2_Rd
;
104 for (i
= 0; i
< 2; i
++) {
105 udelay(mcp
->rw_timeout
);
106 if (Ser4MCSR
& MCSR_CRC
) {
107 ret
= Ser4MCDR2
& 0xffff;
113 printk(KERN_WARNING
"mcp: read timed out\n");
118 static void mcp_sa11x0_enable(struct mcp
*mcp
)
121 Ser4MCCR0
|= MCCR0_MCE
;
124 static void mcp_sa11x0_disable(struct mcp
*mcp
)
126 Ser4MCCR0
&= ~MCCR0_MCE
;
132 static struct mcp_ops mcp_sa11x0
= {
133 .set_telecom_divisor
= mcp_sa11x0_set_telecom_divisor
,
134 .set_audio_divisor
= mcp_sa11x0_set_audio_divisor
,
135 .reg_write
= mcp_sa11x0_write
,
136 .reg_read
= mcp_sa11x0_read
,
137 .enable
= mcp_sa11x0_enable
,
138 .disable
= mcp_sa11x0_disable
,
141 static int mcp_sa11x0_probe(struct platform_device
*pdev
)
143 struct mcp_plat_data
*data
= pdev
->dev
.platform_data
;
150 if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
153 mcp
= mcp_host_alloc(&pdev
->dev
, sizeof(struct mcp_sa11x0
));
159 mcp
->owner
= THIS_MODULE
;
160 mcp
->ops
= &mcp_sa11x0
;
161 mcp
->sclk_rate
= data
->sclk_rate
;
162 mcp
->dma_audio_rd
= DMA_Ser4MCP0Rd
;
163 mcp
->dma_audio_wr
= DMA_Ser4MCP0Wr
;
164 mcp
->dma_telco_rd
= DMA_Ser4MCP1Rd
;
165 mcp
->dma_telco_wr
= DMA_Ser4MCP1Wr
;
166 mcp
->gpio_base
= data
->gpio_base
;
168 platform_set_drvdata(pdev
, mcp
);
170 if (machine_is_assabet()) {
171 ASSABET_BCR_set(ASSABET_BCR_CODEC_RST
);
175 * Setup the PPC unit correctly.
178 PPDR
|= PPC_TXD4
| PPC_SCLK
| PPC_SFRM
;
180 PSDR
&= ~(PPC_TXD4
| PPC_SCLK
| PPC_SFRM
);
181 PPSR
&= ~(PPC_TXD4
| PPC_SCLK
| PPC_SFRM
);
184 * Initialise device. Note that we initially
185 * set the sampling rate to minimum.
188 Ser4MCCR1
= data
->mccr1
;
189 Ser4MCCR0
= data
->mccr0
| 0x7f7f;
192 * Calculate the read/write timeout (us) from the bit clock
193 * rate. This is the period for 3 64-bit frames. Always
194 * round this time up.
196 mcp
->rw_timeout
= (64 * 3 * 1000000 + mcp
->sclk_rate
- 1) /
199 ret
= mcp_host_register(mcp
);
204 release_mem_region(0x80060000, 0x60);
205 platform_set_drvdata(pdev
, NULL
);
211 static int mcp_sa11x0_remove(struct platform_device
*dev
)
213 struct mcp
*mcp
= platform_get_drvdata(dev
);
215 platform_set_drvdata(dev
, NULL
);
216 mcp_host_unregister(mcp
);
217 release_mem_region(0x80060000, 0x60);
222 static int mcp_sa11x0_suspend(struct platform_device
*dev
, pm_message_t state
)
224 struct mcp
*mcp
= platform_get_drvdata(dev
);
226 priv(mcp
)->mccr0
= Ser4MCCR0
;
227 priv(mcp
)->mccr1
= Ser4MCCR1
;
228 Ser4MCCR0
&= ~MCCR0_MCE
;
233 static int mcp_sa11x0_resume(struct platform_device
*dev
)
235 struct mcp
*mcp
= platform_get_drvdata(dev
);
237 Ser4MCCR1
= priv(mcp
)->mccr1
;
238 Ser4MCCR0
= priv(mcp
)->mccr0
;
244 * The driver for the SA11x0 MCP port.
246 MODULE_ALIAS("platform:sa11x0-mcp");
248 static struct platform_driver mcp_sa11x0_driver
= {
249 .probe
= mcp_sa11x0_probe
,
250 .remove
= mcp_sa11x0_remove
,
251 .suspend
= mcp_sa11x0_suspend
,
252 .resume
= mcp_sa11x0_resume
,
254 .name
= "sa11x0-mcp",
259 * This needs re-working
261 static int __init
mcp_sa11x0_init(void)
263 return platform_driver_register(&mcp_sa11x0_driver
);
266 static void __exit
mcp_sa11x0_exit(void)
268 platform_driver_unregister(&mcp_sa11x0_driver
);
271 module_init(mcp_sa11x0_init
);
272 module_exit(mcp_sa11x0_exit
);
274 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
275 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
276 MODULE_LICENSE("GPL");