Blame view

drivers/mfd/mcp-sa11x0.c 7.67 KB
5e742ad66   Russell King   [MFD] Add SA11x0 ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  linux/drivers/mfd/mcp-sa11x0.c
   *
   *  Copyright (C) 2001-2005 Russell King
   *
   * 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.
   *
   *  SA11x0 MCP (Multimedia Communications Port) driver.
   *
   *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
   */
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/delay.h>
  #include <linux/spinlock.h>
d052d1bef   Russell King   Create platform_d...
20
  #include <linux/platform_device.h>
c8602edf3   Thomas Kunze   move drivers/mfd/...
21
  #include <linux/mfd/mcp.h>
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
22
  #include <linux/io.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
23

dcea83adc   Russell King   [ARM] Hide ISA DM...
24
  #include <mach/dma.h>
a09e64fbc   Russell King   [ARM] Move includ...
25
  #include <mach/hardware.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
26
27
  #include <asm/mach-types.h>
  #include <asm/system.h>
a09e64fbc   Russell King   [ARM] Move includ...
28
  #include <mach/mcp.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
29

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
30
31
32
33
34
35
36
  /* Register offsets */
  #define MCCR0	0x00
  #define MCDR0	0x08
  #define MCDR1	0x0C
  #define MCDR2	0x10
  #define MCSR	0x18
  #define MCCR1	0x00
5e742ad66   Russell King   [MFD] Add SA11x0 ...
37
38
  
  struct mcp_sa11x0 {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
39
40
41
42
  	u32		mccr0;
  	u32		mccr1;
  	unsigned char	*mccr0_base;
  	unsigned char	*mccr1_base;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
43
44
45
46
47
48
49
  };
  
  #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
  
  static void
  mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
  {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
50
  	struct mcp_sa11x0 *priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
51
52
  
  	divisor /= 32;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
53
54
55
  	priv->mccr0 &= ~0x00007f00;
  	priv->mccr0 |= divisor << 8;
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
56
57
58
59
60
  }
  
  static void
  mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
  {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
61
  	struct mcp_sa11x0 *priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
62
63
  
  	divisor /= 32;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
64
65
66
  	priv->mccr0 &= ~0x0000007f;
  	priv->mccr0 |= divisor;
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
67
68
69
70
71
72
73
74
75
76
77
78
79
  }
  
  /*
   * Write data to the device.  The bit should be set after 3 subframe
   * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
   * We really should try doing something more productive while we
   * wait.
   */
  static void
  mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
  {
  	int ret = -ETIME;
  	int i;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
80
81
  	u32 mcpreg;
  	struct mcp_sa11x0 *priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
82

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
83
84
  	mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
  	__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
85
86
87
  
  	for (i = 0; i < 2; i++) {
  		udelay(mcp->rw_timeout);
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
88
89
  		mcpreg = __raw_readl(priv->mccr0_base + MCSR);
  		if (mcpreg & MCSR_CWC) {
5e742ad66   Russell King   [MFD] Add SA11x0 ...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  			ret = 0;
  			break;
  		}
  	}
  
  	if (ret < 0)
  		printk(KERN_WARNING "mcp: write timed out
  ");
  }
  
  /*
   * Read data from the device.  The bit should be set after 3 subframe
   * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
   * We really should try doing something more productive while we
   * wait.
   */
  static unsigned int
  mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
  {
  	int ret = -ETIME;
  	int i;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
111
112
  	u32 mcpreg;
  	struct mcp_sa11x0 *priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
113

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
114
115
  	mcpreg = reg << 17 | MCDR2_Rd;
  	__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
116
117
118
  
  	for (i = 0; i < 2; i++) {
  		udelay(mcp->rw_timeout);
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
119
120
121
122
  		mcpreg = __raw_readl(priv->mccr0_base + MCSR);
  		if (mcpreg & MCSR_CRC) {
  			ret = __raw_readl(priv->mccr0_base + MCDR2)
  				& 0xffff;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
123
124
125
126
127
128
129
130
131
132
133
134
135
  			break;
  		}
  	}
  
  	if (ret < 0)
  		printk(KERN_WARNING "mcp: read timed out
  ");
  
  	return ret;
  }
  
  static void mcp_sa11x0_enable(struct mcp *mcp)
  {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
136
137
138
139
140
  	struct mcp_sa11x0 *priv = priv(mcp);
  
  	__raw_writel(-1, priv->mccr0_base + MCSR);
  	priv->mccr0 |= MCCR0_MCE;
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
141
142
143
144
  }
  
  static void mcp_sa11x0_disable(struct mcp *mcp)
  {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
145
146
147
148
  	struct mcp_sa11x0 *priv = priv(mcp);
  
  	priv->mccr0 &= ~MCCR0_MCE;
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
149
150
151
152
153
154
155
156
157
158
159
160
161
  }
  
  /*
   * Our methods.
   */
  static struct mcp_ops mcp_sa11x0 = {
  	.set_telecom_divisor	= mcp_sa11x0_set_telecom_divisor,
  	.set_audio_divisor	= mcp_sa11x0_set_audio_divisor,
  	.reg_write		= mcp_sa11x0_write,
  	.reg_read		= mcp_sa11x0_read,
  	.enable			= mcp_sa11x0_enable,
  	.disable		= mcp_sa11x0_disable,
  };
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
162
  static int mcp_sa11x0_probe(struct platform_device *pdev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
163
  {
323cdfc19   Russell King   [MFD] Add SA11x0 ...
164
  	struct mcp_plat_data *data = pdev->dev.platform_data;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
165
166
  	struct mcp *mcp;
  	int ret;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
167
168
169
  	struct mcp_sa11x0 *priv;
  	struct resource *res_mem0, *res_mem1;
  	u32 size0, size1;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
170

323cdfc19   Russell King   [MFD] Add SA11x0 ...
171
  	if (!data)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
172
  		return -ENODEV;
5dd7bf59e   Jochen Friedrich   ARM: sa11x0: Impl...
173
174
  	if (!data->codec)
  		return -ENODEV;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
175
176
177
178
179
180
181
182
183
184
185
  	res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res_mem0)
  		return -ENODEV;
  	size0 = res_mem0->end - res_mem0->start + 1;
  
  	res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  	if (!res_mem1)
  		return -ENODEV;
  	size1 = res_mem1->end - res_mem1->start + 1;
  
  	if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
5e742ad66   Russell King   [MFD] Add SA11x0 ...
186
  		return -EBUSY;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
187
188
189
190
  	if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
  		ret = -EBUSY;
  		goto release;
  	}
5e742ad66   Russell King   [MFD] Add SA11x0 ...
191
192
193
  	mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
  	if (!mcp) {
  		ret = -ENOMEM;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
194
  		goto release2;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
195
  	}
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
196
  	priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
197
198
  	mcp->owner		= THIS_MODULE;
  	mcp->ops		= &mcp_sa11x0;
323cdfc19   Russell King   [MFD] Add SA11x0 ...
199
  	mcp->sclk_rate		= data->sclk_rate;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
200
201
202
203
204
205
206
207
  	mcp->dma_audio_rd	= DDAR_DevAdd(res_mem0->start + MCDR0)
  				+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
  	mcp->dma_audio_wr	= DDAR_DevAdd(res_mem0->start + MCDR0)
  				+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
  	mcp->dma_telco_rd	= DDAR_DevAdd(res_mem0->start + MCDR1)
  				+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
  	mcp->dma_telco_wr	= DDAR_DevAdd(res_mem0->start + MCDR1)
  				+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
5dd7bf59e   Jochen Friedrich   ARM: sa11x0: Impl...
208
  	mcp->codec		= data->codec;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
209

3ae5eaec1   Russell King   [DRIVER MODEL] Co...
210
  	platform_set_drvdata(pdev, mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
211

323cdfc19   Russell King   [MFD] Add SA11x0 ...
212
213
214
215
  	/*
  	 * Initialise device.  Note that we initially
  	 * set the sampling rate to minimum.
  	 */
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
216
217
218
219
220
221
222
223
  	priv->mccr0_base = ioremap(res_mem0->start, size0);
  	priv->mccr1_base = ioremap(res_mem1->start, size1);
  
  	__raw_writel(-1, priv->mccr0_base + MCSR);
  	priv->mccr1 = data->mccr1;
  	priv->mccr0 = data->mccr0 | 0x7f7f;
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  	__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
224
225
226
227
228
229
230
231
  
  	/*
  	 * Calculate the read/write timeout (us) from the bit clock
  	 * rate.  This is the period for 3 64-bit frames.  Always
  	 * round this time up.
  	 */
  	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
  			  mcp->sclk_rate;
5dd7bf59e   Jochen Friedrich   ARM: sa11x0: Impl...
232
  	ret = mcp_host_register(mcp, data->codec_pdata);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
233
234
  	if (ret == 0)
  		goto out;
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
235
236
   release2:
  	release_mem_region(res_mem1->start, size1);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
237
   release:
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
238
  	release_mem_region(res_mem0->start, size0);
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
239
  	platform_set_drvdata(pdev, NULL);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
240
241
242
243
  
   out:
  	return ret;
  }
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
244
  static int mcp_sa11x0_remove(struct platform_device *pdev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
245
  {
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
246
247
248
249
  	struct mcp *mcp = platform_get_drvdata(pdev);
  	struct mcp_sa11x0 *priv = priv(mcp);
  	struct resource *res_mem;
  	u32 size;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
250

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
251
  	platform_set_drvdata(pdev, NULL);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
252
  	mcp_host_unregister(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
253

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
254
255
256
257
258
259
260
261
262
263
264
265
  	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (res_mem) {
  		size = res_mem->end - res_mem->start + 1;
  		release_mem_region(res_mem->start, size);
  	}
  	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  	if (res_mem) {
  		size = res_mem->end - res_mem->start + 1;
  		release_mem_region(res_mem->start, size);
  	}
  	iounmap(priv->mccr0_base);
  	iounmap(priv->mccr1_base);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
266
267
  	return 0;
  }
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
268
  static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
269
  {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
270
  	struct mcp *mcp = platform_get_drvdata(dev);
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
271
272
  	struct mcp_sa11x0 *priv = priv(mcp);
  	u32 mccr0;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
273

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
274
275
  	mccr0 = priv->mccr0 & ~MCCR0_MCE;
  	__raw_writel(mccr0, priv->mccr0_base + MCCR0);
9480e307c   Russell King   [PATCH] DRIVER MO...
276

5e742ad66   Russell King   [MFD] Add SA11x0 ...
277
278
  	return 0;
  }
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
279
  static int mcp_sa11x0_resume(struct platform_device *dev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
280
  {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
281
  	struct mcp *mcp = platform_get_drvdata(dev);
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
282
  	struct mcp_sa11x0 *priv = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
283

af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
284
285
  	__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  	__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
9480e307c   Russell King   [PATCH] DRIVER MO...
286

5e742ad66   Russell King   [MFD] Add SA11x0 ...
287
288
289
290
291
292
  	return 0;
  }
  
  /*
   * The driver for the SA11x0 MCP port.
   */
4f46d6e7e   Kay Sievers   mfd: fix platform...
293
  MODULE_ALIAS("platform:sa11x0-mcp");
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
294
  static struct platform_driver mcp_sa11x0_driver = {
5e742ad66   Russell King   [MFD] Add SA11x0 ...
295
296
297
298
  	.probe		= mcp_sa11x0_probe,
  	.remove		= mcp_sa11x0_remove,
  	.suspend	= mcp_sa11x0_suspend,
  	.resume		= mcp_sa11x0_resume,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
299
300
  	.driver		= {
  		.name	= "sa11x0-mcp",
af9081ae6   Jochen Friedrich   ARM: sa1100: Refa...
301
  		.owner  = THIS_MODULE,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
302
  	},
5e742ad66   Russell King   [MFD] Add SA11x0 ...
303
304
305
306
307
  };
  
  /*
   * This needs re-working
   */
65349d60d   Mark Brown   mfd: Convert MFD ...
308
  module_platform_driver(mcp_sa11x0_driver);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
309
310
311
312
  
  MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
  MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
  MODULE_LICENSE("GPL");