]> Pileus Git - ~andy/linux/blob - drivers/mfd/mcp-sa11x0.c
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[~andy/linux] / drivers / mfd / mcp-sa11x0.c
1 /*
2  *  linux/drivers/mfd/mcp-sa11x0.c
3  *
4  *  Copyright (C) 2001-2005 Russell King
5  *
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.
9  *
10  *  SA11x0 MCP (Multimedia Communications Port) driver.
11  *
12  *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
13  */
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/io.h>
17 #include <linux/errno.h>
18 #include <linux/kernel.h>
19 #include <linux/delay.h>
20 #include <linux/spinlock.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm.h>
23 #include <linux/mfd/mcp.h>
24
25 #include <mach/hardware.h>
26 #include <asm/mach-types.h>
27 #include <asm/system.h>
28 #include <mach/mcp.h>
29
30 #define DRIVER_NAME "sa11x0-mcp"
31
32 struct mcp_sa11x0 {
33         void __iomem    *base0;
34         void __iomem    *base1;
35         u32             mccr0;
36         u32             mccr1;
37 };
38
39 /* Register offsets */
40 #define MCCR0(m)        ((m)->base0 + 0x00)
41 #define MCDR0(m)        ((m)->base0 + 0x08)
42 #define MCDR1(m)        ((m)->base0 + 0x0c)
43 #define MCDR2(m)        ((m)->base0 + 0x10)
44 #define MCSR(m)         ((m)->base0 + 0x18)
45 #define MCCR1(m)        ((m)->base1 + 0x00)
46
47 #define priv(mcp)       ((struct mcp_sa11x0 *)mcp_priv(mcp))
48
49 static void
50 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
51 {
52         struct mcp_sa11x0 *m = priv(mcp);
53
54         divisor /= 32;
55
56         m->mccr0 &= ~0x00007f00;
57         m->mccr0 |= divisor << 8;
58         writel_relaxed(m->mccr0, MCCR0(m));
59 }
60
61 static void
62 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
63 {
64         struct mcp_sa11x0 *m = priv(mcp);
65
66         divisor /= 32;
67
68         m->mccr0 &= ~0x0000007f;
69         m->mccr0 |= divisor;
70         writel_relaxed(m->mccr0, MCCR0(m));
71 }
72
73 /*
74  * Write data to the device.  The bit should be set after 3 subframe
75  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
76  * We really should try doing something more productive while we
77  * wait.
78  */
79 static void
80 mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
81 {
82         struct mcp_sa11x0 *m = priv(mcp);
83         int ret = -ETIME;
84         int i;
85
86         writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
87
88         for (i = 0; i < 2; i++) {
89                 udelay(mcp->rw_timeout);
90                 if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
91                         ret = 0;
92                         break;
93                 }
94         }
95
96         if (ret < 0)
97                 printk(KERN_WARNING "mcp: write timed out\n");
98 }
99
100 /*
101  * Read data from the device.  The bit should be set after 3 subframe
102  * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
103  * We really should try doing something more productive while we
104  * wait.
105  */
106 static unsigned int
107 mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
108 {
109         struct mcp_sa11x0 *m = priv(mcp);
110         int ret = -ETIME;
111         int i;
112
113         writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
114
115         for (i = 0; i < 2; i++) {
116                 udelay(mcp->rw_timeout);
117                 if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
118                         ret = readl_relaxed(MCDR2(m)) & 0xffff;
119                         break;
120                 }
121         }
122
123         if (ret < 0)
124                 printk(KERN_WARNING "mcp: read timed out\n");
125
126         return ret;
127 }
128
129 static void mcp_sa11x0_enable(struct mcp *mcp)
130 {
131         struct mcp_sa11x0 *m = priv(mcp);
132
133         writel(-1, MCSR(m));
134         m->mccr0 |= MCCR0_MCE;
135         writel_relaxed(m->mccr0, MCCR0(m));
136 }
137
138 static void mcp_sa11x0_disable(struct mcp *mcp)
139 {
140         struct mcp_sa11x0 *m = priv(mcp);
141
142         m->mccr0 &= ~MCCR0_MCE;
143         writel_relaxed(m->mccr0, MCCR0(m));
144 }
145
146 /*
147  * Our methods.
148  */
149 static struct mcp_ops mcp_sa11x0 = {
150         .set_telecom_divisor    = mcp_sa11x0_set_telecom_divisor,
151         .set_audio_divisor      = mcp_sa11x0_set_audio_divisor,
152         .reg_write              = mcp_sa11x0_write,
153         .reg_read               = mcp_sa11x0_read,
154         .enable                 = mcp_sa11x0_enable,
155         .disable                = mcp_sa11x0_disable,
156 };
157
158 static int mcp_sa11x0_probe(struct platform_device *dev)
159 {
160         struct mcp_plat_data *data = dev->dev.platform_data;
161         struct resource *mem0, *mem1;
162         struct mcp_sa11x0 *m;
163         struct mcp *mcp;
164         int ret;
165
166         if (!data)
167                 return -ENODEV;
168
169         mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
170         mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
171         if (!mem0 || !mem1)
172                 return -ENXIO;
173
174         if (!request_mem_region(mem0->start, resource_size(mem0),
175                                 DRIVER_NAME)) {
176                 ret = -EBUSY;
177                 goto err_mem0;
178         }
179
180         if (!request_mem_region(mem1->start, resource_size(mem1),
181                                 DRIVER_NAME)) {
182                 ret = -EBUSY;
183                 goto err_mem1;
184         }
185
186         mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
187         if (!mcp) {
188                 ret = -ENOMEM;
189                 goto err_alloc;
190         }
191
192         mcp->owner              = THIS_MODULE;
193         mcp->ops                = &mcp_sa11x0;
194         mcp->sclk_rate          = data->sclk_rate;
195
196         m = priv(mcp);
197         m->mccr0 = data->mccr0 | 0x7f7f;
198         m->mccr1 = data->mccr1;
199
200         m->base0 = ioremap(mem0->start, resource_size(mem0));
201         m->base1 = ioremap(mem1->start, resource_size(mem1));
202         if (!m->base0 || !m->base1) {
203                 ret = -ENOMEM;
204                 goto err_ioremap;
205         }
206
207         platform_set_drvdata(dev, mcp);
208
209         /*
210          * Initialise device.  Note that we initially
211          * set the sampling rate to minimum.
212          */
213         writel_relaxed(-1, MCSR(m));
214         writel_relaxed(m->mccr1, MCCR1(m));
215         writel_relaxed(m->mccr0, MCCR0(m));
216
217         /*
218          * Calculate the read/write timeout (us) from the bit clock
219          * rate.  This is the period for 3 64-bit frames.  Always
220          * round this time up.
221          */
222         mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
223                           mcp->sclk_rate;
224
225         ret = mcp_host_add(mcp, data->codec_pdata);
226         if (ret == 0)
227                 return 0;
228
229         platform_set_drvdata(dev, NULL);
230
231  err_ioremap:
232         iounmap(m->base1);
233         iounmap(m->base0);
234         mcp_host_free(mcp);
235  err_alloc:
236         release_mem_region(mem1->start, resource_size(mem1));
237  err_mem1:
238         release_mem_region(mem0->start, resource_size(mem0));
239  err_mem0:
240         return ret;
241 }
242
243 static int mcp_sa11x0_remove(struct platform_device *dev)
244 {
245         struct mcp *mcp = platform_get_drvdata(dev);
246         struct mcp_sa11x0 *m = priv(mcp);
247         struct resource *mem0, *mem1;
248
249         if (m->mccr0 & MCCR0_MCE)
250                 dev_warn(&dev->dev,
251                          "device left active (missing disable call?)\n");
252
253         mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
254         mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
255
256         platform_set_drvdata(dev, NULL);
257         mcp_host_del(mcp);
258         iounmap(m->base1);
259         iounmap(m->base0);
260         mcp_host_free(mcp);
261         release_mem_region(mem1->start, resource_size(mem1));
262         release_mem_region(mem0->start, resource_size(mem0));
263
264         return 0;
265 }
266
267 #ifdef CONFIG_PM_SLEEP
268 static int mcp_sa11x0_suspend(struct device *dev)
269 {
270         struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
271
272         if (m->mccr0 & MCCR0_MCE)
273                 dev_warn(dev, "device left active (missing disable call?)\n");
274
275         writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
276
277         return 0;
278 }
279
280 static int mcp_sa11x0_resume(struct device *dev)
281 {
282         struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
283
284         writel_relaxed(m->mccr1, MCCR1(m));
285         writel_relaxed(m->mccr0, MCCR0(m));
286
287         return 0;
288 }
289 #endif
290
291 static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
292 #ifdef CONFIG_PM_SLEEP
293         .suspend = mcp_sa11x0_suspend,
294         .freeze = mcp_sa11x0_suspend,
295         .poweroff = mcp_sa11x0_suspend,
296         .resume_noirq = mcp_sa11x0_resume,
297         .thaw_noirq = mcp_sa11x0_resume,
298         .restore_noirq = mcp_sa11x0_resume,
299 #endif
300 };
301
302 static struct platform_driver mcp_sa11x0_driver = {
303         .probe          = mcp_sa11x0_probe,
304         .remove         = mcp_sa11x0_remove,
305         .driver         = {
306                 .name   = DRIVER_NAME,
307                 .owner  = THIS_MODULE,
308                 .pm     = &mcp_sa11x0_pm_ops,
309         },
310 };
311
312 /*
313  * This needs re-working
314  */
315 module_platform_driver(mcp_sa11x0_driver);
316
317 MODULE_ALIAS("platform:" DRIVER_NAME);
318 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
319 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
320 MODULE_LICENSE("GPL");