Root/
1 | /* |
2 | * linux/drivers/mfd/mcp-core.c |
3 | * |
4 | * Copyright (C) 2001 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 | * Generic MCP (Multimedia Communications Port) layer. All MCP locking |
11 | * is solely held within this file. |
12 | */ |
13 | #include <linux/module.h> |
14 | #include <linux/init.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/smp.h> |
17 | #include <linux/device.h> |
18 | #include <linux/slab.h> |
19 | #include <linux/string.h> |
20 | #include <linux/mfd/mcp.h> |
21 | |
22 | |
23 | #define to_mcp(d) container_of(d, struct mcp, attached_device) |
24 | #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) |
25 | |
26 | static int mcp_bus_match(struct device *dev, struct device_driver *drv) |
27 | { |
28 | return 1; |
29 | } |
30 | |
31 | static int mcp_bus_probe(struct device *dev) |
32 | { |
33 | struct mcp *mcp = to_mcp(dev); |
34 | struct mcp_driver *drv = to_mcp_driver(dev->driver); |
35 | |
36 | return drv->probe(mcp); |
37 | } |
38 | |
39 | static int mcp_bus_remove(struct device *dev) |
40 | { |
41 | struct mcp *mcp = to_mcp(dev); |
42 | struct mcp_driver *drv = to_mcp_driver(dev->driver); |
43 | |
44 | drv->remove(mcp); |
45 | return 0; |
46 | } |
47 | |
48 | static struct bus_type mcp_bus_type = { |
49 | .name = "mcp", |
50 | .match = mcp_bus_match, |
51 | .probe = mcp_bus_probe, |
52 | .remove = mcp_bus_remove, |
53 | }; |
54 | |
55 | /** |
56 | * mcp_set_telecom_divisor - set the telecom divisor |
57 | * @mcp: MCP interface structure |
58 | * @div: SIB clock divisor |
59 | * |
60 | * Set the telecom divisor on the MCP interface. The resulting |
61 | * sample rate is SIBCLOCK/div. |
62 | */ |
63 | void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div) |
64 | { |
65 | unsigned long flags; |
66 | |
67 | spin_lock_irqsave(&mcp->lock, flags); |
68 | mcp->ops->set_telecom_divisor(mcp, div); |
69 | spin_unlock_irqrestore(&mcp->lock, flags); |
70 | } |
71 | EXPORT_SYMBOL(mcp_set_telecom_divisor); |
72 | |
73 | /** |
74 | * mcp_set_audio_divisor - set the audio divisor |
75 | * @mcp: MCP interface structure |
76 | * @div: SIB clock divisor |
77 | * |
78 | * Set the audio divisor on the MCP interface. |
79 | */ |
80 | void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div) |
81 | { |
82 | unsigned long flags; |
83 | |
84 | spin_lock_irqsave(&mcp->lock, flags); |
85 | mcp->ops->set_audio_divisor(mcp, div); |
86 | spin_unlock_irqrestore(&mcp->lock, flags); |
87 | } |
88 | EXPORT_SYMBOL(mcp_set_audio_divisor); |
89 | |
90 | /** |
91 | * mcp_reg_write - write a device register |
92 | * @mcp: MCP interface structure |
93 | * @reg: 4-bit register index |
94 | * @val: 16-bit data value |
95 | * |
96 | * Write a device register. The MCP interface must be enabled |
97 | * to prevent this function hanging. |
98 | */ |
99 | void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) |
100 | { |
101 | unsigned long flags; |
102 | |
103 | spin_lock_irqsave(&mcp->lock, flags); |
104 | mcp->ops->reg_write(mcp, reg, val); |
105 | spin_unlock_irqrestore(&mcp->lock, flags); |
106 | } |
107 | EXPORT_SYMBOL(mcp_reg_write); |
108 | |
109 | /** |
110 | * mcp_reg_read - read a device register |
111 | * @mcp: MCP interface structure |
112 | * @reg: 4-bit register index |
113 | * |
114 | * Read a device register and return its value. The MCP interface |
115 | * must be enabled to prevent this function hanging. |
116 | */ |
117 | unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) |
118 | { |
119 | unsigned long flags; |
120 | unsigned int val; |
121 | |
122 | spin_lock_irqsave(&mcp->lock, flags); |
123 | val = mcp->ops->reg_read(mcp, reg); |
124 | spin_unlock_irqrestore(&mcp->lock, flags); |
125 | |
126 | return val; |
127 | } |
128 | EXPORT_SYMBOL(mcp_reg_read); |
129 | |
130 | /** |
131 | * mcp_enable - enable the MCP interface |
132 | * @mcp: MCP interface to enable |
133 | * |
134 | * Enable the MCP interface. Each call to mcp_enable will need |
135 | * a corresponding call to mcp_disable to disable the interface. |
136 | */ |
137 | void mcp_enable(struct mcp *mcp) |
138 | { |
139 | unsigned long flags; |
140 | spin_lock_irqsave(&mcp->lock, flags); |
141 | if (mcp->use_count++ == 0) |
142 | mcp->ops->enable(mcp); |
143 | spin_unlock_irqrestore(&mcp->lock, flags); |
144 | } |
145 | EXPORT_SYMBOL(mcp_enable); |
146 | |
147 | /** |
148 | * mcp_disable - disable the MCP interface |
149 | * @mcp: MCP interface to disable |
150 | * |
151 | * Disable the MCP interface. The MCP interface will only be |
152 | * disabled once the number of calls to mcp_enable matches the |
153 | * number of calls to mcp_disable. |
154 | */ |
155 | void mcp_disable(struct mcp *mcp) |
156 | { |
157 | unsigned long flags; |
158 | |
159 | spin_lock_irqsave(&mcp->lock, flags); |
160 | if (--mcp->use_count == 0) |
161 | mcp->ops->disable(mcp); |
162 | spin_unlock_irqrestore(&mcp->lock, flags); |
163 | } |
164 | EXPORT_SYMBOL(mcp_disable); |
165 | |
166 | static void mcp_release(struct device *dev) |
167 | { |
168 | struct mcp *mcp = container_of(dev, struct mcp, attached_device); |
169 | |
170 | kfree(mcp); |
171 | } |
172 | |
173 | struct mcp *mcp_host_alloc(struct device *parent, size_t size) |
174 | { |
175 | struct mcp *mcp; |
176 | |
177 | mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL); |
178 | if (mcp) { |
179 | spin_lock_init(&mcp->lock); |
180 | device_initialize(&mcp->attached_device); |
181 | mcp->attached_device.parent = parent; |
182 | mcp->attached_device.bus = &mcp_bus_type; |
183 | mcp->attached_device.dma_mask = parent->dma_mask; |
184 | mcp->attached_device.release = mcp_release; |
185 | } |
186 | return mcp; |
187 | } |
188 | EXPORT_SYMBOL(mcp_host_alloc); |
189 | |
190 | int mcp_host_add(struct mcp *mcp, void *pdata) |
191 | { |
192 | mcp->attached_device.platform_data = pdata; |
193 | dev_set_name(&mcp->attached_device, "mcp0"); |
194 | return device_add(&mcp->attached_device); |
195 | } |
196 | EXPORT_SYMBOL(mcp_host_add); |
197 | |
198 | void mcp_host_del(struct mcp *mcp) |
199 | { |
200 | device_del(&mcp->attached_device); |
201 | } |
202 | EXPORT_SYMBOL(mcp_host_del); |
203 | |
204 | void mcp_host_free(struct mcp *mcp) |
205 | { |
206 | put_device(&mcp->attached_device); |
207 | } |
208 | EXPORT_SYMBOL(mcp_host_free); |
209 | |
210 | int mcp_driver_register(struct mcp_driver *mcpdrv) |
211 | { |
212 | mcpdrv->drv.bus = &mcp_bus_type; |
213 | return driver_register(&mcpdrv->drv); |
214 | } |
215 | EXPORT_SYMBOL(mcp_driver_register); |
216 | |
217 | void mcp_driver_unregister(struct mcp_driver *mcpdrv) |
218 | { |
219 | driver_unregister(&mcpdrv->drv); |
220 | } |
221 | EXPORT_SYMBOL(mcp_driver_unregister); |
222 | |
223 | static int __init mcp_init(void) |
224 | { |
225 | return bus_register(&mcp_bus_type); |
226 | } |
227 | |
228 | static void __exit mcp_exit(void) |
229 | { |
230 | bus_unregister(&mcp_bus_type); |
231 | } |
232 | |
233 | module_init(mcp_init); |
234 | module_exit(mcp_exit); |
235 | |
236 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); |
237 | MODULE_DESCRIPTION("Core multimedia communications port driver"); |
238 | MODULE_LICENSE("GPL"); |
239 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9