diff options
Diffstat (limited to 'arch/arm/mach-ux500/mbox.c')
-rw-r--r-- | arch/arm/mach-ux500/mbox.c | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox.c new file mode 100644 index 000000000000..63435389c544 --- /dev/null +++ b/arch/arm/mach-ux500/mbox.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson. | ||
4 | * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson. | ||
5 | * License terms: GNU General Public License (GPL), version 2. | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Mailbox nomenclature: | ||
10 | * | ||
11 | * APE MODEM | ||
12 | * mbox pairX | ||
13 | * .......................... | ||
14 | * . . | ||
15 | * . peer . | ||
16 | * . send ---- . | ||
17 | * . --> | | . | ||
18 | * . | | . | ||
19 | * . ---- . | ||
20 | * . . | ||
21 | * . local . | ||
22 | * . rec ---- . | ||
23 | * . | | <-- . | ||
24 | * . | | . | ||
25 | * . ---- . | ||
26 | * ......................... | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/errno.h> | ||
35 | #include <linux/io.h> | ||
36 | #include <linux/irq.h> | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/debugfs.h> | ||
39 | #include <linux/seq_file.h> | ||
40 | #include <linux/completion.h> | ||
41 | #include <mach/mbox.h> | ||
42 | |||
43 | #define MBOX_NAME "mbox" | ||
44 | |||
45 | #define MBOX_FIFO_DATA 0x000 | ||
46 | #define MBOX_FIFO_ADD 0x004 | ||
47 | #define MBOX_FIFO_REMOVE 0x008 | ||
48 | #define MBOX_FIFO_THRES_FREE 0x00C | ||
49 | #define MBOX_FIFO_THRES_OCCUP 0x010 | ||
50 | #define MBOX_FIFO_STATUS 0x014 | ||
51 | |||
52 | #define MBOX_DISABLE_IRQ 0x4 | ||
53 | #define MBOX_ENABLE_IRQ 0x0 | ||
54 | #define MBOX_LATCH 1 | ||
55 | |||
56 | /* Global list of all mailboxes */ | ||
57 | static struct list_head mboxs = LIST_HEAD_INIT(mboxs); | ||
58 | |||
59 | static struct mbox *get_mbox_with_id(u8 id) | ||
60 | { | ||
61 | u8 i; | ||
62 | struct list_head *pos = &mboxs; | ||
63 | for (i = 0; i <= id; i++) | ||
64 | pos = pos->next; | ||
65 | |||
66 | return (struct mbox *) list_entry(pos, struct mbox, list); | ||
67 | } | ||
68 | |||
69 | int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block) | ||
70 | { | ||
71 | int res = 0; | ||
72 | |||
73 | spin_lock(&mbox->lock); | ||
74 | |||
75 | dev_dbg(&(mbox->pdev->dev), | ||
76 | "About to buffer 0x%X to mailbox 0x%X." | ||
77 | " ri = %d, wi = %d\n", | ||
78 | mbox_msg, (u32)mbox, mbox->read_index, | ||
79 | mbox->write_index); | ||
80 | |||
81 | /* Check if write buffer is full */ | ||
82 | while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) { | ||
83 | if (!block) { | ||
84 | dev_dbg(&(mbox->pdev->dev), | ||
85 | "Buffer full in non-blocking call! " | ||
86 | "Returning -ENOMEM!\n"); | ||
87 | res = -ENOMEM; | ||
88 | goto exit; | ||
89 | } | ||
90 | spin_unlock(&mbox->lock); | ||
91 | dev_dbg(&(mbox->pdev->dev), | ||
92 | "Buffer full in blocking call! Sleeping...\n"); | ||
93 | mbox->client_blocked = 1; | ||
94 | wait_for_completion(&mbox->buffer_available); | ||
95 | dev_dbg(&(mbox->pdev->dev), | ||
96 | "Blocking send was woken up! Trying again...\n"); | ||
97 | spin_lock(&mbox->lock); | ||
98 | } | ||
99 | |||
100 | mbox->buffer[mbox->write_index] = mbox_msg; | ||
101 | mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE; | ||
102 | |||
103 | /* | ||
104 | * Indicate that we want an IRQ as soon as there is a slot | ||
105 | * in the FIFO | ||
106 | */ | ||
107 | writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); | ||
108 | |||
109 | exit: | ||
110 | spin_unlock(&mbox->lock); | ||
111 | return res; | ||
112 | } | ||
113 | EXPORT_SYMBOL(mbox_send); | ||
114 | |||
115 | #if defined(CONFIG_DEBUG_FS) | ||
116 | /* | ||
117 | * Expected input: <value> <nbr sends> | ||
118 | * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times | ||
119 | */ | ||
120 | static ssize_t mbox_write_fifo(struct device *dev, | ||
121 | struct device_attribute *attr, | ||
122 | const char *buf, | ||
123 | size_t count) | ||
124 | { | ||
125 | unsigned long mbox_mess; | ||
126 | unsigned long nbr_sends; | ||
127 | unsigned long i; | ||
128 | char int_buf[16]; | ||
129 | char *token; | ||
130 | char *val; | ||
131 | |||
132 | struct mbox *mbox = (struct mbox *) dev->platform_data; | ||
133 | |||
134 | strncpy((char *) &int_buf, buf, sizeof(int_buf)); | ||
135 | token = (char *) &int_buf; | ||
136 | |||
137 | /* Parse message */ | ||
138 | val = strsep(&token, " "); | ||
139 | if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0)) | ||
140 | mbox_mess = 0xDEADBEEF; | ||
141 | |||
142 | val = strsep(&token, " "); | ||
143 | if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0)) | ||
144 | nbr_sends = 1; | ||
145 | |||
146 | dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n", | ||
147 | mbox_mess, nbr_sends, (u32) mbox); | ||
148 | |||
149 | for (i = 0; i < nbr_sends; i++) | ||
150 | mbox_send(mbox, mbox_mess, true); | ||
151 | |||
152 | return count; | ||
153 | } | ||
154 | |||
155 | static ssize_t mbox_read_fifo(struct device *dev, | ||
156 | struct device_attribute *attr, | ||
157 | char *buf) | ||
158 | { | ||
159 | int mbox_value; | ||
160 | struct mbox *mbox = (struct mbox *) dev->platform_data; | ||
161 | |||
162 | if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0) | ||
163 | return sprintf(buf, "Mailbox is empty\n"); | ||
164 | |||
165 | mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA); | ||
166 | writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE)); | ||
167 | |||
168 | return sprintf(buf, "0x%X\n", mbox_value); | ||
169 | } | ||
170 | |||
171 | static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo); | ||
172 | |||
173 | static int mbox_show(struct seq_file *s, void *data) | ||
174 | { | ||
175 | struct list_head *pos; | ||
176 | u8 mbox_index = 0; | ||
177 | |||
178 | list_for_each(pos, &mboxs) { | ||
179 | struct mbox *m = | ||
180 | (struct mbox *) list_entry(pos, struct mbox, list); | ||
181 | if (m == NULL) { | ||
182 | seq_printf(s, | ||
183 | "Unable to retrieve mailbox %d\n", | ||
184 | mbox_index); | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | spin_lock(&m->lock); | ||
189 | if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) { | ||
190 | seq_printf(s, "MAILBOX %d not setup or corrupt\n", | ||
191 | mbox_index); | ||
192 | spin_unlock(&m->lock); | ||
193 | continue; | ||
194 | } | ||
195 | |||
196 | seq_printf(s, | ||
197 | "===========================\n" | ||
198 | " MAILBOX %d\n" | ||
199 | " PEER MAILBOX DUMP\n" | ||
200 | "---------------------------\n" | ||
201 | "FIFO: 0x%X (%d)\n" | ||
202 | "Free Threshold: 0x%.2X (%d)\n" | ||
203 | "Occupied Threshold: 0x%.2X (%d)\n" | ||
204 | "Status: 0x%.2X (%d)\n" | ||
205 | " Free spaces (ot): %d (%d)\n" | ||
206 | " Occup spaces (ot): %d (%d)\n" | ||
207 | "===========================\n" | ||
208 | " LOCAL MAILBOX DUMP\n" | ||
209 | "---------------------------\n" | ||
210 | "FIFO: 0x%.X (%d)\n" | ||
211 | "Free Threshold: 0x%.2X (%d)\n" | ||
212 | "Occupied Threshold: 0x%.2X (%d)\n" | ||
213 | "Status: 0x%.2X (%d)\n" | ||
214 | " Free spaces (ot): %d (%d)\n" | ||
215 | " Occup spaces (ot): %d (%d)\n" | ||
216 | "===========================\n" | ||
217 | "write_index: %d\n" | ||
218 | "read_index : %d\n" | ||
219 | "===========================\n" | ||
220 | "\n", | ||
221 | mbox_index, | ||
222 | readl(m->virtbase_peer + MBOX_FIFO_DATA), | ||
223 | readl(m->virtbase_peer + MBOX_FIFO_DATA), | ||
224 | readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE), | ||
225 | readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE), | ||
226 | readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP), | ||
227 | readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP), | ||
228 | readl(m->virtbase_peer + MBOX_FIFO_STATUS), | ||
229 | readl(m->virtbase_peer + MBOX_FIFO_STATUS), | ||
230 | (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7, | ||
231 | (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1, | ||
232 | (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7, | ||
233 | (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1, | ||
234 | readl(m->virtbase_local + MBOX_FIFO_DATA), | ||
235 | readl(m->virtbase_local + MBOX_FIFO_DATA), | ||
236 | readl(m->virtbase_local + MBOX_FIFO_THRES_FREE), | ||
237 | readl(m->virtbase_local + MBOX_FIFO_THRES_FREE), | ||
238 | readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP), | ||
239 | readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP), | ||
240 | readl(m->virtbase_local + MBOX_FIFO_STATUS), | ||
241 | readl(m->virtbase_local + MBOX_FIFO_STATUS), | ||
242 | (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7, | ||
243 | (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1, | ||
244 | (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7, | ||
245 | (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1, | ||
246 | m->write_index, m->read_index); | ||
247 | mbox_index++; | ||
248 | spin_unlock(&m->lock); | ||
249 | } | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int mbox_open(struct inode *inode, struct file *file) | ||
255 | { | ||
256 | return single_open(file, mbox_show, NULL); | ||
257 | } | ||
258 | |||
259 | static const struct file_operations mbox_operations = { | ||
260 | .owner = THIS_MODULE, | ||
261 | .open = mbox_open, | ||
262 | .read = seq_read, | ||
263 | .llseek = seq_lseek, | ||
264 | .release = single_release, | ||
265 | }; | ||
266 | #endif | ||
267 | |||
268 | static irqreturn_t mbox_irq(int irq, void *arg) | ||
269 | { | ||
270 | u32 mbox_value; | ||
271 | int nbr_occup; | ||
272 | int nbr_free; | ||
273 | struct mbox *mbox = (struct mbox *) arg; | ||
274 | |||
275 | spin_lock(&mbox->lock); | ||
276 | |||
277 | dev_dbg(&(mbox->pdev->dev), | ||
278 | "mbox IRQ [%d] received. ri = %d, wi = %d\n", | ||
279 | irq, mbox->read_index, mbox->write_index); | ||
280 | |||
281 | /* | ||
282 | * Check if we have any outgoing messages, and if there is space for | ||
283 | * them in the FIFO. | ||
284 | */ | ||
285 | if (mbox->read_index != mbox->write_index) { | ||
286 | /* | ||
287 | * Check by reading FREE for LOCAL since that indicates | ||
288 | * OCCUP for PEER | ||
289 | */ | ||
290 | nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS) | ||
291 | >> 4) & 0x7; | ||
292 | dev_dbg(&(mbox->pdev->dev), | ||
293 | "Status indicates %d empty spaces in the FIFO!\n", | ||
294 | nbr_free); | ||
295 | |||
296 | while ((nbr_free > 0) && | ||
297 | (mbox->read_index != mbox->write_index)) { | ||
298 | /* Write the message and latch it into the FIFO */ | ||
299 | writel(mbox->buffer[mbox->read_index], | ||
300 | (mbox->virtbase_peer + MBOX_FIFO_DATA)); | ||
301 | writel(MBOX_LATCH, | ||
302 | (mbox->virtbase_peer + MBOX_FIFO_ADD)); | ||
303 | dev_dbg(&(mbox->pdev->dev), | ||
304 | "Wrote message 0x%X to addr 0x%X\n", | ||
305 | mbox->buffer[mbox->read_index], | ||
306 | (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA)); | ||
307 | |||
308 | nbr_free--; | ||
309 | mbox->read_index = | ||
310 | (mbox->read_index + 1) % MBOX_BUF_SIZE; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Check if we still want IRQ:s when there is free | ||
315 | * space to send | ||
316 | */ | ||
317 | if (mbox->read_index != mbox->write_index) { | ||
318 | dev_dbg(&(mbox->pdev->dev), | ||
319 | "Still have messages to send, but FIFO full. " | ||
320 | "Request IRQ again!\n"); | ||
321 | writel(MBOX_ENABLE_IRQ, | ||
322 | mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); | ||
323 | } else { | ||
324 | dev_dbg(&(mbox->pdev->dev), | ||
325 | "No more messages to send. " | ||
326 | "Do not request IRQ again!\n"); | ||
327 | writel(MBOX_DISABLE_IRQ, | ||
328 | mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Check if we can signal any blocked clients that it is OK to | ||
333 | * start buffering again | ||
334 | */ | ||
335 | if (mbox->client_blocked && | ||
336 | (((mbox->write_index + 1) % MBOX_BUF_SIZE) | ||
337 | != mbox->read_index)) { | ||
338 | dev_dbg(&(mbox->pdev->dev), | ||
339 | "Waking up blocked client\n"); | ||
340 | complete(&mbox->buffer_available); | ||
341 | mbox->client_blocked = 0; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /* Check if we have any incoming messages */ | ||
346 | nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7; | ||
347 | if (nbr_occup == 0) | ||
348 | goto exit; | ||
349 | |||
350 | if (mbox->cb == NULL) { | ||
351 | dev_dbg(&(mbox->pdev->dev), "No receive callback registered, " | ||
352 | "leaving %d incoming messages in fifo!\n", nbr_occup); | ||
353 | goto exit; | ||
354 | } | ||
355 | |||
356 | /* Read and acknowledge the message */ | ||
357 | mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA); | ||
358 | writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE)); | ||
359 | |||
360 | /* Notify consumer of new mailbox message */ | ||
361 | dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n", | ||
362 | mbox_value); | ||
363 | mbox->cb(mbox_value, mbox->client_data); | ||
364 | |||
365 | exit: | ||
366 | dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n", | ||
367 | mbox->read_index, mbox->write_index); | ||
368 | spin_unlock(&mbox->lock); | ||
369 | |||
370 | return IRQ_HANDLED; | ||
371 | } | ||
372 | |||
373 | /* Setup is executed once for each mbox pair */ | ||
374 | struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv) | ||
375 | { | ||
376 | struct resource *resource; | ||
377 | int irq; | ||
378 | int res; | ||
379 | struct mbox *mbox; | ||
380 | |||
381 | mbox = get_mbox_with_id(mbox_id); | ||
382 | if (mbox == NULL) { | ||
383 | dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n", | ||
384 | mbox_id); | ||
385 | goto exit; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Check if mailbox has been allocated to someone else, | ||
390 | * otherwise allocate it | ||
391 | */ | ||
392 | if (mbox->allocated) { | ||
393 | dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n", | ||
394 | mbox_id); | ||
395 | mbox = NULL; | ||
396 | goto exit; | ||
397 | } | ||
398 | mbox->allocated = true; | ||
399 | |||
400 | dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n", | ||
401 | mbox_id, (u32)mbox); | ||
402 | |||
403 | mbox->client_data = priv; | ||
404 | mbox->cb = mbox_cb; | ||
405 | |||
406 | /* Get addr for peer mailbox and ioremap it */ | ||
407 | resource = platform_get_resource_byname(mbox->pdev, | ||
408 | IORESOURCE_MEM, | ||
409 | "mbox_peer"); | ||
410 | if (resource == NULL) { | ||
411 | dev_err(&(mbox->pdev->dev), | ||
412 | "Unable to retrieve mbox peer resource\n"); | ||
413 | mbox = NULL; | ||
414 | goto exit; | ||
415 | } | ||
416 | dev_dbg(&(mbox->pdev->dev), | ||
417 | "Resource name: %s start: 0x%X, end: 0x%X\n", | ||
418 | resource->name, resource->start, resource->end); | ||
419 | mbox->virtbase_peer = | ||
420 | ioremap(resource->start, resource->end - resource->start); | ||
421 | if (!mbox->virtbase_peer) { | ||
422 | dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n"); | ||
423 | mbox = NULL; | ||
424 | goto exit; | ||
425 | } | ||
426 | dev_dbg(&(mbox->pdev->dev), | ||
427 | "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n", | ||
428 | resource->start, resource->end, (u32) mbox->virtbase_peer); | ||
429 | |||
430 | /* Get addr for local mailbox and ioremap it */ | ||
431 | resource = platform_get_resource_byname(mbox->pdev, | ||
432 | IORESOURCE_MEM, | ||
433 | "mbox_local"); | ||
434 | if (resource == NULL) { | ||
435 | dev_err(&(mbox->pdev->dev), | ||
436 | "Unable to retrieve mbox local resource\n"); | ||
437 | mbox = NULL; | ||
438 | goto exit; | ||
439 | } | ||
440 | dev_dbg(&(mbox->pdev->dev), | ||
441 | "Resource name: %s start: 0x%X, end: 0x%X\n", | ||
442 | resource->name, resource->start, resource->end); | ||
443 | mbox->virtbase_local = | ||
444 | ioremap(resource->start, resource->end - resource->start); | ||
445 | if (!mbox->virtbase_local) { | ||
446 | dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n"); | ||
447 | mbox = NULL; | ||
448 | goto exit; | ||
449 | } | ||
450 | dev_dbg(&(mbox->pdev->dev), | ||
451 | "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n", | ||
452 | resource->start, resource->end, (u32) mbox->virtbase_peer); | ||
453 | |||
454 | init_completion(&mbox->buffer_available); | ||
455 | mbox->client_blocked = 0; | ||
456 | |||
457 | /* Get IRQ for mailbox and allocate it */ | ||
458 | irq = platform_get_irq_byname(mbox->pdev, "mbox_irq"); | ||
459 | if (irq < 0) { | ||
460 | dev_err(&(mbox->pdev->dev), | ||
461 | "Unable to retrieve mbox irq resource\n"); | ||
462 | mbox = NULL; | ||
463 | goto exit; | ||
464 | } | ||
465 | |||
466 | dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq); | ||
467 | res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox); | ||
468 | if (res < 0) { | ||
469 | dev_err(&(mbox->pdev->dev), | ||
470 | "Unable to allocate mbox irq %d\n", irq); | ||
471 | mbox = NULL; | ||
472 | goto exit; | ||
473 | } | ||
474 | |||
475 | /* Set up mailbox to not launch IRQ on free space in mailbox */ | ||
476 | writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE); | ||
477 | |||
478 | /* | ||
479 | * Set up mailbox to launch IRQ on new message if we have | ||
480 | * a callback set. If not, do not raise IRQ, but keep message | ||
481 | * in FIFO for manual retrieval | ||
482 | */ | ||
483 | if (mbox_cb != NULL) | ||
484 | writel(MBOX_ENABLE_IRQ, | ||
485 | mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP); | ||
486 | else | ||
487 | writel(MBOX_DISABLE_IRQ, | ||
488 | mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP); | ||
489 | |||
490 | #if defined(CONFIG_DEBUG_FS) | ||
491 | res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo); | ||
492 | if (res != 0) | ||
493 | dev_warn(&(mbox->pdev->dev), | ||
494 | "Unable to create mbox sysfs entry"); | ||
495 | |||
496 | (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL, | ||
497 | NULL, &mbox_operations); | ||
498 | #endif | ||
499 | |||
500 | dev_info(&(mbox->pdev->dev), | ||
501 | "Mailbox driver with index %d initated!\n", mbox_id); | ||
502 | |||
503 | exit: | ||
504 | return mbox; | ||
505 | } | ||
506 | EXPORT_SYMBOL(mbox_setup); | ||
507 | |||
508 | |||
509 | int __init mbox_probe(struct platform_device *pdev) | ||
510 | { | ||
511 | struct mbox local_mbox; | ||
512 | struct mbox *mbox; | ||
513 | int res = 0; | ||
514 | dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev); | ||
515 | |||
516 | memset(&local_mbox, 0x0, sizeof(struct mbox)); | ||
517 | |||
518 | /* Associate our mbox data with the platform device */ | ||
519 | res = platform_device_add_data(pdev, | ||
520 | (void *) &local_mbox, | ||
521 | sizeof(struct mbox)); | ||
522 | if (res != 0) { | ||
523 | dev_err(&(pdev->dev), | ||
524 | "Unable to allocate driver platform data!\n"); | ||
525 | goto exit; | ||
526 | } | ||
527 | |||
528 | mbox = (struct mbox *) pdev->dev.platform_data; | ||
529 | mbox->pdev = pdev; | ||
530 | mbox->write_index = 0; | ||
531 | mbox->read_index = 0; | ||
532 | |||
533 | INIT_LIST_HEAD(&(mbox->list)); | ||
534 | list_add_tail(&(mbox->list), &mboxs); | ||
535 | |||
536 | sprintf(mbox->name, "%s", MBOX_NAME); | ||
537 | spin_lock_init(&mbox->lock); | ||
538 | |||
539 | dev_info(&(pdev->dev), "Mailbox driver loaded\n"); | ||
540 | |||
541 | exit: | ||
542 | return res; | ||
543 | } | ||
544 | |||
545 | static struct platform_driver mbox_driver = { | ||
546 | .driver = { | ||
547 | .name = MBOX_NAME, | ||
548 | .owner = THIS_MODULE, | ||
549 | }, | ||
550 | }; | ||
551 | |||
552 | static int __init mbox_init(void) | ||
553 | { | ||
554 | return platform_driver_probe(&mbox_driver, mbox_probe); | ||
555 | } | ||
556 | |||
557 | module_init(mbox_init); | ||
558 | |||
559 | void __exit mbox_exit(void) | ||
560 | { | ||
561 | platform_driver_unregister(&mbox_driver); | ||
562 | } | ||
563 | |||
564 | module_exit(mbox_exit); | ||
565 | |||
566 | MODULE_LICENSE("GPL"); | ||
567 | MODULE_DESCRIPTION("MBOX driver"); | ||