Blame view

drivers/mfd/mcp-sa11x0.c 6.87 KB
84a14ae8c   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
5e742ad66   Russell King   [MFD] Add SA11x0 ...
2
3
4
5
6
  /*
   *  linux/drivers/mfd/mcp-sa11x0.c
   *
   *  Copyright (C) 2001-2005 Russell King
   *
5e742ad66   Russell King   [MFD] Add SA11x0 ...
7
8
9
10
11
   *  SA11x0 MCP (Multimedia Communications Port) driver.
   *
   *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
   */
  #include <linux/module.h>
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
12
  #include <linux/io.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
13
14
15
16
  #include <linux/errno.h>
  #include <linux/kernel.h>
  #include <linux/delay.h>
  #include <linux/spinlock.h>
d052d1bef   Russell King   Create platform_d...
17
  #include <linux/platform_device.h>
2796e3973   Russell King   MFD: mcp-sa11x0: ...
18
  #include <linux/pm.h>
c8602edf3   Thomas Kunze   move drivers/mfd/...
19
  #include <linux/mfd/mcp.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
20

a09e64fbc   Russell King   [ARM] Move includ...
21
  #include <mach/hardware.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
22
  #include <asm/mach-types.h>
a1fd844c6   Arnd Bergmann   ARM: sa1100: move...
23
  #include <linux/platform_data/mfd-mcp-sa11x0.h>
5e742ad66   Russell King   [MFD] Add SA11x0 ...
24

c4592ce4e   Russell King   MFD: mcp-sa11x0: ...
25
  #define DRIVER_NAME "sa11x0-mcp"
5e742ad66   Russell King   [MFD] Add SA11x0 ...
26
27
  
  struct mcp_sa11x0 {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
28
29
30
31
  	void __iomem	*base0;
  	void __iomem	*base1;
  	u32		mccr0;
  	u32		mccr1;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
32
  };
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
33
34
35
36
37
38
39
  /* Register offsets */
  #define MCCR0(m)	((m)->base0 + 0x00)
  #define MCDR0(m)	((m)->base0 + 0x08)
  #define MCDR1(m)	((m)->base0 + 0x0c)
  #define MCDR2(m)	((m)->base0 + 0x10)
  #define MCSR(m)		((m)->base0 + 0x18)
  #define MCCR1(m)	((m)->base1 + 0x00)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
40
41
42
43
44
  #define priv(mcp)	((struct mcp_sa11x0 *)mcp_priv(mcp))
  
  static void
  mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
45
  	struct mcp_sa11x0 *m = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
46
47
  
  	divisor /= 32;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
48
49
50
  	m->mccr0 &= ~0x00007f00;
  	m->mccr0 |= divisor << 8;
  	writel_relaxed(m->mccr0, MCCR0(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
51
52
53
54
55
  }
  
  static void
  mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
56
  	struct mcp_sa11x0 *m = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
57
58
  
  	divisor /= 32;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
59
60
61
  	m->mccr0 &= ~0x0000007f;
  	m->mccr0 |= divisor;
  	writel_relaxed(m->mccr0, MCCR0(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
62
63
64
65
66
67
68
69
70
71
72
  }
  
  /*
   * 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)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
73
  	struct mcp_sa11x0 *m = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
74
75
  	int ret = -ETIME;
  	int i;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
76
  	writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
77
78
79
  
  	for (i = 0; i < 2; i++) {
  		udelay(mcp->rw_timeout);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
80
  		if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
5e742ad66   Russell King   [MFD] Add SA11x0 ...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  			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)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
100
  	struct mcp_sa11x0 *m = priv(mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
101
102
  	int ret = -ETIME;
  	int i;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
103
  	writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
104
105
106
  
  	for (i = 0; i < 2; i++) {
  		udelay(mcp->rw_timeout);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
107
108
  		if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
  			ret = readl_relaxed(MCDR2(m)) & 0xffff;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
109
110
111
112
113
114
115
116
117
118
119
120
121
  			break;
  		}
  	}
  
  	if (ret < 0)
  		printk(KERN_WARNING "mcp: read timed out
  ");
  
  	return ret;
  }
  
  static void mcp_sa11x0_enable(struct mcp *mcp)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
122
123
124
125
126
  	struct mcp_sa11x0 *m = priv(mcp);
  
  	writel(-1, MCSR(m));
  	m->mccr0 |= MCCR0_MCE;
  	writel_relaxed(m->mccr0, MCCR0(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
127
128
129
130
  }
  
  static void mcp_sa11x0_disable(struct mcp *mcp)
  {
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
131
132
133
134
  	struct mcp_sa11x0 *m = priv(mcp);
  
  	m->mccr0 &= ~MCCR0_MCE;
  	writel_relaxed(m->mccr0, MCCR0(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
135
136
137
138
139
140
141
142
143
144
145
146
147
  }
  
  /*
   * 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,
  };
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
148
  static int mcp_sa11x0_probe(struct platform_device *dev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
149
  {
334a41ce9   Jingoo Han   mfd: Use dev_get_...
150
  	struct mcp_plat_data *data = dev_get_platdata(&dev->dev);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
151
152
  	struct resource *mem0, *mem1;
  	struct mcp_sa11x0 *m;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
153
154
  	struct mcp *mcp;
  	int ret;
323cdfc19   Russell King   [MFD] Add SA11x0 ...
155
  	if (!data)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
156
  		return -ENODEV;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
157
158
159
160
161
162
163
164
165
166
  	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
  	if (!mem0 || !mem1)
  		return -ENXIO;
  
  	if (!request_mem_region(mem0->start, resource_size(mem0),
  				DRIVER_NAME)) {
  		ret = -EBUSY;
  		goto err_mem0;
  	}
5e742ad66   Russell King   [MFD] Add SA11x0 ...
167

45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
168
169
170
171
172
173
174
  	if (!request_mem_region(mem1->start, resource_size(mem1),
  				DRIVER_NAME)) {
  		ret = -EBUSY;
  		goto err_mem1;
  	}
  
  	mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
175
176
  	if (!mcp) {
  		ret = -ENOMEM;
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
177
  		goto err_alloc;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
178
179
180
181
  	}
  
  	mcp->owner		= THIS_MODULE;
  	mcp->ops		= &mcp_sa11x0;
323cdfc19   Russell King   [MFD] Add SA11x0 ...
182
  	mcp->sclk_rate		= data->sclk_rate;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
183

45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
184
185
186
187
188
189
190
191
192
193
194
195
  	m = priv(mcp);
  	m->mccr0 = data->mccr0 | 0x7f7f;
  	m->mccr1 = data->mccr1;
  
  	m->base0 = ioremap(mem0->start, resource_size(mem0));
  	m->base1 = ioremap(mem1->start, resource_size(mem1));
  	if (!m->base0 || !m->base1) {
  		ret = -ENOMEM;
  		goto err_ioremap;
  	}
  
  	platform_set_drvdata(dev, mcp);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
196

216f63c41   Russell King   Revert "ARM: sa11...
197
  	/*
323cdfc19   Russell King   [MFD] Add SA11x0 ...
198
199
200
  	 * Initialise device.  Note that we initially
  	 * set the sampling rate to minimum.
  	 */
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
201
202
203
  	writel_relaxed(-1, MCSR(m));
  	writel_relaxed(m->mccr1, MCCR1(m));
  	writel_relaxed(m->mccr0, MCCR0(m));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
204
205
206
207
208
209
210
211
  
  	/*
  	 * 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;
abe06082d   Russell King   MFD: mcp/ucb1x00:...
212
  	ret = mcp_host_add(mcp, data->codec_pdata);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
213
  	if (ret == 0)
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
214
  		return 0;
5e742ad66   Russell King   [MFD] Add SA11x0 ...
215

45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
216
217
218
219
220
221
222
223
224
   err_ioremap:
  	iounmap(m->base1);
  	iounmap(m->base0);
  	mcp_host_free(mcp);
   err_alloc:
  	release_mem_region(mem1->start, resource_size(mem1));
   err_mem1:
  	release_mem_region(mem0->start, resource_size(mem0));
   err_mem0:
5e742ad66   Russell King   [MFD] Add SA11x0 ...
225
226
  	return ret;
  }
216f63c41   Russell King   Revert "ARM: sa11...
227
  static int mcp_sa11x0_remove(struct platform_device *dev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
228
  {
216f63c41   Russell King   Revert "ARM: sa11...
229
  	struct mcp *mcp = platform_get_drvdata(dev);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
230
231
  	struct mcp_sa11x0 *m = priv(mcp);
  	struct resource *mem0, *mem1;
a4b54acf9   Russell King   MFD: mcp-sa11x0: ...
232
233
234
235
  	if (m->mccr0 & MCCR0_MCE)
  		dev_warn(&dev->dev,
  			 "device left active (missing disable call?)
  ");
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
236
237
  	mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
238

30816ac04   Russell King   MFD: mcp-core: sa...
239
  	mcp_host_del(mcp);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
240
241
  	iounmap(m->base1);
  	iounmap(m->base0);
30816ac04   Russell King   MFD: mcp-core: sa...
242
  	mcp_host_free(mcp);
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
243
244
  	release_mem_region(mem1->start, resource_size(mem1));
  	release_mem_region(mem0->start, resource_size(mem0));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
245
246
247
  
  	return 0;
  }
2796e3973   Russell King   MFD: mcp-sa11x0: ...
248
249
  #ifdef CONFIG_PM_SLEEP
  static int mcp_sa11x0_suspend(struct device *dev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
250
  {
2796e3973   Russell King   MFD: mcp-sa11x0: ...
251
  	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
252

a4b54acf9   Russell King   MFD: mcp-sa11x0: ...
253
254
255
  	if (m->mccr0 & MCCR0_MCE)
  		dev_warn(dev, "device left active (missing disable call?)
  ");
45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
256
  	writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
9480e307c   Russell King   [PATCH] DRIVER MO...
257

5e742ad66   Russell King   [MFD] Add SA11x0 ...
258
259
  	return 0;
  }
2796e3973   Russell King   MFD: mcp-sa11x0: ...
260
  static int mcp_sa11x0_resume(struct device *dev)
5e742ad66   Russell King   [MFD] Add SA11x0 ...
261
  {
2796e3973   Russell King   MFD: mcp-sa11x0: ...
262
  	struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
5e742ad66   Russell King   [MFD] Add SA11x0 ...
263

45c7f75fd   Russell King   MFD: mcp-sa11x0: ...
264
265
  	writel_relaxed(m->mccr1, MCCR1(m));
  	writel_relaxed(m->mccr0, MCCR0(m));
9480e307c   Russell King   [PATCH] DRIVER MO...
266

5e742ad66   Russell King   [MFD] Add SA11x0 ...
267
268
  	return 0;
  }
2796e3973   Russell King   MFD: mcp-sa11x0: ...
269
270
271
  #endif
  
  static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
a6aecae29   Russell King   MFD: mcp-sa11x0: ...
272
273
274
275
276
277
278
279
  #ifdef CONFIG_PM_SLEEP
  	.suspend = mcp_sa11x0_suspend,
  	.freeze = mcp_sa11x0_suspend,
  	.poweroff = mcp_sa11x0_suspend,
  	.resume_noirq = mcp_sa11x0_resume,
  	.thaw_noirq = mcp_sa11x0_resume,
  	.restore_noirq = mcp_sa11x0_resume,
  #endif
2796e3973   Russell King   MFD: mcp-sa11x0: ...
280
  };
5e742ad66   Russell King   [MFD] Add SA11x0 ...
281

3ae5eaec1   Russell King   [DRIVER MODEL] Co...
282
  static struct platform_driver mcp_sa11x0_driver = {
5e742ad66   Russell King   [MFD] Add SA11x0 ...
283
284
  	.probe		= mcp_sa11x0_probe,
  	.remove		= mcp_sa11x0_remove,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
285
  	.driver		= {
c4592ce4e   Russell King   MFD: mcp-sa11x0: ...
286
  		.name	= DRIVER_NAME,
2796e3973   Russell King   MFD: mcp-sa11x0: ...
287
  		.pm	= &mcp_sa11x0_pm_ops,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
288
  	},
5e742ad66   Russell King   [MFD] Add SA11x0 ...
289
290
291
292
293
  };
  
  /*
   * This needs re-working
   */
65349d60d   Mark Brown   mfd: Convert MFD ...
294
  module_platform_driver(mcp_sa11x0_driver);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
295

c4592ce4e   Russell King   MFD: mcp-sa11x0: ...
296
  MODULE_ALIAS("platform:" DRIVER_NAME);
5e742ad66   Russell King   [MFD] Add SA11x0 ...
297
298
299
  MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
  MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
  MODULE_LICENSE("GPL");