Blame view
drivers/mfd/mcp-sa11x0.c
7.67 KB
5e742ad66 [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 Create platform_d... |
20 |
#include <linux/platform_device.h> |
c8602edf3 move drivers/mfd/... |
21 |
#include <linux/mfd/mcp.h> |
af9081ae6 ARM: sa1100: Refa... |
22 |
#include <linux/io.h> |
5e742ad66 [MFD] Add SA11x0 ... |
23 |
|
dcea83adc [ARM] Hide ISA DM... |
24 |
#include <mach/dma.h> |
a09e64fbc [ARM] Move includ... |
25 |
#include <mach/hardware.h> |
5e742ad66 [MFD] Add SA11x0 ... |
26 27 |
#include <asm/mach-types.h> #include <asm/system.h> |
a09e64fbc [ARM] Move includ... |
28 |
#include <mach/mcp.h> |
5e742ad66 [MFD] Add SA11x0 ... |
29 |
|
af9081ae6 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 [MFD] Add SA11x0 ... |
37 38 |
struct mcp_sa11x0 { |
af9081ae6 ARM: sa1100: Refa... |
39 40 41 42 |
u32 mccr0; u32 mccr1; unsigned char *mccr0_base; unsigned char *mccr1_base; |
5e742ad66 [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 ARM: sa1100: Refa... |
50 |
struct mcp_sa11x0 *priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
51 52 |
divisor /= 32; |
af9081ae6 ARM: sa1100: Refa... |
53 54 55 |
priv->mccr0 &= ~0x00007f00; priv->mccr0 |= divisor << 8; __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); |
5e742ad66 [MFD] Add SA11x0 ... |
56 57 58 59 60 |
} static void mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) { |
af9081ae6 ARM: sa1100: Refa... |
61 |
struct mcp_sa11x0 *priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
62 63 |
divisor /= 32; |
af9081ae6 ARM: sa1100: Refa... |
64 65 66 |
priv->mccr0 &= ~0x0000007f; priv->mccr0 |= divisor; __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); |
5e742ad66 [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 ARM: sa1100: Refa... |
80 81 |
u32 mcpreg; struct mcp_sa11x0 *priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
82 |
|
af9081ae6 ARM: sa1100: Refa... |
83 84 |
mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff); __raw_writel(mcpreg, priv->mccr0_base + MCDR2); |
5e742ad66 [MFD] Add SA11x0 ... |
85 86 87 |
for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); |
af9081ae6 ARM: sa1100: Refa... |
88 89 |
mcpreg = __raw_readl(priv->mccr0_base + MCSR); if (mcpreg & MCSR_CWC) { |
5e742ad66 [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 ARM: sa1100: Refa... |
111 112 |
u32 mcpreg; struct mcp_sa11x0 *priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
113 |
|
af9081ae6 ARM: sa1100: Refa... |
114 115 |
mcpreg = reg << 17 | MCDR2_Rd; __raw_writel(mcpreg, priv->mccr0_base + MCDR2); |
5e742ad66 [MFD] Add SA11x0 ... |
116 117 118 |
for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); |
af9081ae6 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 [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 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 [MFD] Add SA11x0 ... |
141 142 143 144 |
} static void mcp_sa11x0_disable(struct mcp *mcp) { |
af9081ae6 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 [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 [DRIVER MODEL] Co... |
162 |
static int mcp_sa11x0_probe(struct platform_device *pdev) |
5e742ad66 [MFD] Add SA11x0 ... |
163 |
{ |
323cdfc19 [MFD] Add SA11x0 ... |
164 |
struct mcp_plat_data *data = pdev->dev.platform_data; |
5e742ad66 [MFD] Add SA11x0 ... |
165 166 |
struct mcp *mcp; int ret; |
af9081ae6 ARM: sa1100: Refa... |
167 168 169 |
struct mcp_sa11x0 *priv; struct resource *res_mem0, *res_mem1; u32 size0, size1; |
5e742ad66 [MFD] Add SA11x0 ... |
170 |
|
323cdfc19 [MFD] Add SA11x0 ... |
171 |
if (!data) |
5e742ad66 [MFD] Add SA11x0 ... |
172 |
return -ENODEV; |
5dd7bf59e ARM: sa11x0: Impl... |
173 174 |
if (!data->codec) return -ENODEV; |
af9081ae6 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 [MFD] Add SA11x0 ... |
186 |
return -EBUSY; |
af9081ae6 ARM: sa1100: Refa... |
187 188 189 190 |
if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) { ret = -EBUSY; goto release; } |
5e742ad66 [MFD] Add SA11x0 ... |
191 192 193 |
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); if (!mcp) { ret = -ENOMEM; |
af9081ae6 ARM: sa1100: Refa... |
194 |
goto release2; |
5e742ad66 [MFD] Add SA11x0 ... |
195 |
} |
af9081ae6 ARM: sa1100: Refa... |
196 |
priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
197 198 |
mcp->owner = THIS_MODULE; mcp->ops = &mcp_sa11x0; |
323cdfc19 [MFD] Add SA11x0 ... |
199 |
mcp->sclk_rate = data->sclk_rate; |
af9081ae6 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 ARM: sa11x0: Impl... |
208 |
mcp->codec = data->codec; |
5e742ad66 [MFD] Add SA11x0 ... |
209 |
|
3ae5eaec1 [DRIVER MODEL] Co... |
210 |
platform_set_drvdata(pdev, mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
211 |
|
323cdfc19 [MFD] Add SA11x0 ... |
212 213 214 215 |
/* * Initialise device. Note that we initially * set the sampling rate to minimum. */ |
af9081ae6 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 [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 ARM: sa11x0: Impl... |
232 |
ret = mcp_host_register(mcp, data->codec_pdata); |
5e742ad66 [MFD] Add SA11x0 ... |
233 234 |
if (ret == 0) goto out; |
af9081ae6 ARM: sa1100: Refa... |
235 236 |
release2: release_mem_region(res_mem1->start, size1); |
5e742ad66 [MFD] Add SA11x0 ... |
237 |
release: |
af9081ae6 ARM: sa1100: Refa... |
238 |
release_mem_region(res_mem0->start, size0); |
3ae5eaec1 [DRIVER MODEL] Co... |
239 |
platform_set_drvdata(pdev, NULL); |
5e742ad66 [MFD] Add SA11x0 ... |
240 241 242 243 |
out: return ret; } |
af9081ae6 ARM: sa1100: Refa... |
244 |
static int mcp_sa11x0_remove(struct platform_device *pdev) |
5e742ad66 [MFD] Add SA11x0 ... |
245 |
{ |
af9081ae6 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 [MFD] Add SA11x0 ... |
250 |
|
af9081ae6 ARM: sa1100: Refa... |
251 |
platform_set_drvdata(pdev, NULL); |
5e742ad66 [MFD] Add SA11x0 ... |
252 |
mcp_host_unregister(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
253 |
|
af9081ae6 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 [MFD] Add SA11x0 ... |
266 267 |
return 0; } |
3ae5eaec1 [DRIVER MODEL] Co... |
268 |
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) |
5e742ad66 [MFD] Add SA11x0 ... |
269 |
{ |
3ae5eaec1 [DRIVER MODEL] Co... |
270 |
struct mcp *mcp = platform_get_drvdata(dev); |
af9081ae6 ARM: sa1100: Refa... |
271 272 |
struct mcp_sa11x0 *priv = priv(mcp); u32 mccr0; |
5e742ad66 [MFD] Add SA11x0 ... |
273 |
|
af9081ae6 ARM: sa1100: Refa... |
274 275 |
mccr0 = priv->mccr0 & ~MCCR0_MCE; __raw_writel(mccr0, priv->mccr0_base + MCCR0); |
9480e307c [PATCH] DRIVER MO... |
276 |
|
5e742ad66 [MFD] Add SA11x0 ... |
277 278 |
return 0; } |
3ae5eaec1 [DRIVER MODEL] Co... |
279 |
static int mcp_sa11x0_resume(struct platform_device *dev) |
5e742ad66 [MFD] Add SA11x0 ... |
280 |
{ |
3ae5eaec1 [DRIVER MODEL] Co... |
281 |
struct mcp *mcp = platform_get_drvdata(dev); |
af9081ae6 ARM: sa1100: Refa... |
282 |
struct mcp_sa11x0 *priv = priv(mcp); |
5e742ad66 [MFD] Add SA11x0 ... |
283 |
|
af9081ae6 ARM: sa1100: Refa... |
284 285 |
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1); |
9480e307c [PATCH] DRIVER MO... |
286 |
|
5e742ad66 [MFD] Add SA11x0 ... |
287 288 289 290 291 292 |
return 0; } /* * The driver for the SA11x0 MCP port. */ |
4f46d6e7e mfd: fix platform... |
293 |
MODULE_ALIAS("platform:sa11x0-mcp"); |
3ae5eaec1 [DRIVER MODEL] Co... |
294 |
static struct platform_driver mcp_sa11x0_driver = { |
5e742ad66 [MFD] Add SA11x0 ... |
295 296 297 298 |
.probe = mcp_sa11x0_probe, .remove = mcp_sa11x0_remove, .suspend = mcp_sa11x0_suspend, .resume = mcp_sa11x0_resume, |
3ae5eaec1 [DRIVER MODEL] Co... |
299 300 |
.driver = { .name = "sa11x0-mcp", |
af9081ae6 ARM: sa1100: Refa... |
301 |
.owner = THIS_MODULE, |
3ae5eaec1 [DRIVER MODEL] Co... |
302 |
}, |
5e742ad66 [MFD] Add SA11x0 ... |
303 304 305 306 307 |
}; /* * This needs re-working */ |
65349d60d mfd: Convert MFD ... |
308 |
module_platform_driver(mcp_sa11x0_driver); |
5e742ad66 [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"); |