diff options
author | Richard Zhu <r65037@freescale.com> | 2014-04-11 03:11:14 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:58:21 -0400 |
commit | 39e6a62bc0f89d34c7b62294aef343eac38ce982 (patch) | |
tree | 3f407d7b81ef9ef1787bddc6bca719601a63aa69 | |
parent | d9bc7e358e1494e29da5acc4c33c1144cdbd31f2 (diff) |
ENGR00308060-3 mcc: add sema4 driver required by mcc
- add linux sema4 driver, that mandatory required by mcc.
- use volatile types in sema4 structure
- align the port definiton a9 is 1, m4 is 2.
Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/imx_mcc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/char/imx_mcc/Makefile | 5 | ||||
-rw-r--r-- | drivers/char/imx_mcc/imx_sema4.c | 416 | ||||
-rw-r--r-- | include/linux/imx_sema4.h | 71 |
6 files changed, 504 insertions, 0 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 09b813479de5..39b6a58e8237 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -627,5 +627,7 @@ config MXS_VIIM | |||
627 | Support for access to MXS Virtual IIM device, most people should say N here. | 627 | Support for access to MXS Virtual IIM device, most people should say N here. |
628 | 628 | ||
629 | source "drivers/char/xillybus/Kconfig" | 629 | source "drivers/char/xillybus/Kconfig" |
630 | |||
631 | source "drivers/char/imx_mcc/Kconfig" | ||
630 | endmenu | 632 | endmenu |
631 | 633 | ||
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index e27e9fb1bfd7..5a4efdacc5e2 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -65,3 +65,4 @@ js-rtc-y = rtc.o | |||
65 | 65 | ||
66 | obj-$(CONFIG_TILE_SROM) += tile-srom.o | 66 | obj-$(CONFIG_TILE_SROM) += tile-srom.o |
67 | obj-$(CONFIG_XILLYBUS) += xillybus/ | 67 | obj-$(CONFIG_XILLYBUS) += xillybus/ |
68 | obj-$(CONFIG_HAVE_IMX_MCC) += imx_mcc/ | ||
diff --git a/drivers/char/imx_mcc/Kconfig b/drivers/char/imx_mcc/Kconfig new file mode 100644 index 000000000000..1f892f8daccb --- /dev/null +++ b/drivers/char/imx_mcc/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # imx mcc | ||
3 | # | ||
4 | |||
5 | config IMX_SEMA4 | ||
6 | bool "IMX SEMA4 driver" | ||
7 | depends on SOC_IMX6SX | ||
8 | help | ||
9 | Support for IMX SEMA4 driver, most people should say N here. | ||
diff --git a/drivers/char/imx_mcc/Makefile b/drivers/char/imx_mcc/Makefile new file mode 100644 index 000000000000..4e7a91691b39 --- /dev/null +++ b/drivers/char/imx_mcc/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for imx mcc | ||
3 | # | ||
4 | # | ||
5 | obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o | ||
diff --git a/drivers/char/imx_mcc/imx_sema4.c b/drivers/char/imx_mcc/imx_sema4.c new file mode 100644 index 000000000000..12d68a86dfe3 --- /dev/null +++ b/drivers/char/imx_mcc/imx_sema4.c | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * The code contained herein is licensed under the GNU General Public | ||
7 | * License. You may obtain a copy of the GNU General Public License | ||
8 | * Version 2 or later at the following locations: | ||
9 | * | ||
10 | * http://www.opensource.org/licenses/gpl-license.html | ||
11 | * http://www.gnu.org/copyleft/gpl.html | ||
12 | */ | ||
13 | |||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/wait.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/imx_sema4.h> | ||
24 | |||
25 | static struct imx_sema4_mutex_device *imx6_sema4; | ||
26 | |||
27 | /*! | ||
28 | * \brief mutex create function. | ||
29 | * | ||
30 | * This function allocates imx_sema4_mutex structure and returns a handle | ||
31 | * to it. The mutex to be created is identified by SEMA4 device number and mutex | ||
32 | * (gate) number. The handle is used to reference the created mutex in calls to | ||
33 | * other imx_sema4_mutex API functions. This function is to be called only | ||
34 | * once for each mutex. | ||
35 | * | ||
36 | * \param[in] dev_num SEMA4 device (module) number. | ||
37 | * \param[in] mutex_num Mutex (gate) number. | ||
38 | * | ||
39 | * \return NULL (Failure.) | ||
40 | * \return imx_sema4_mutex (Success.) | ||
41 | */ | ||
42 | struct imx_sema4_mutex * | ||
43 | imx_sema4_mutex_create(u32 dev_num, u32 mutex_num) | ||
44 | { | ||
45 | struct imx_sema4_mutex *mutex_ptr = NULL; | ||
46 | |||
47 | if ((mutex_num > SEMA4_NUM_GATES) || dev_num >= SEMA4_NUM_DEVICES) | ||
48 | goto out; | ||
49 | |||
50 | if (imx6_sema4->cpine_val & (1 < mutex_num)) { | ||
51 | pr_err("Error: requiring a allocated sema4.\n"); | ||
52 | pr_err("mutex_num %d cpine_val 0x%08x.\n", | ||
53 | mutex_num, imx6_sema4->cpine_val); | ||
54 | } | ||
55 | mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL); | ||
56 | if (!mutex_ptr) | ||
57 | goto out; | ||
58 | imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr; | ||
59 | imx6_sema4->alloced |= 1 < mutex_num; | ||
60 | imx6_sema4->cpine_val |= idx_sema4[mutex_num]; | ||
61 | writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE); | ||
62 | |||
63 | mutex_ptr->valid = CORE_MUTEX_VALID; | ||
64 | mutex_ptr->gate_num = mutex_num; | ||
65 | init_waitqueue_head(&mutex_ptr->wait_q); | ||
66 | |||
67 | out: | ||
68 | return mutex_ptr; | ||
69 | } | ||
70 | EXPORT_SYMBOL(imx_sema4_mutex_create); | ||
71 | |||
72 | /*! | ||
73 | * \brief mutex destroy function. | ||
74 | * | ||
75 | * This function destroys a mutex. | ||
76 | * | ||
77 | * \param[in] mutex_ptr Pointer to mutex structure. | ||
78 | * | ||
79 | * \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.) | ||
80 | * \return MQX_INVALID_PARAMETER (Wrong input parameter.) | ||
81 | * \return COREMUTEX_OK (Success.) | ||
82 | * | ||
83 | */ | ||
84 | int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr) | ||
85 | { | ||
86 | u32 mutex_num; | ||
87 | |||
88 | if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) | ||
89 | return -EINVAL; | ||
90 | |||
91 | mutex_num = mutex_ptr->gate_num; | ||
92 | if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) { | ||
93 | pr_err("Error: trying to destory a un-allocated sema4.\n"); | ||
94 | pr_err("mutex_num %d cpine_val 0x%08x.\n", | ||
95 | mutex_num, imx6_sema4->cpine_val); | ||
96 | } | ||
97 | imx6_sema4->mutex_ptr[mutex_num] = NULL; | ||
98 | imx6_sema4->alloced &= ~(1 << mutex_num); | ||
99 | imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]); | ||
100 | writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE); | ||
101 | |||
102 | kfree(mutex_ptr); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | EXPORT_SYMBOL(imx_sema4_mutex_destroy); | ||
107 | |||
108 | /*! | ||
109 | * \brief Lock the mutex, shouldn't be interruted by INT. | ||
110 | * | ||
111 | * This function attempts to lock a mutex. If the mutex is already locked | ||
112 | * by another task the function return -EBUSY, and tell invoker wait until | ||
113 | * it is possible to lock the mutex. | ||
114 | * | ||
115 | * \param[in] mutex_ptr Pointer to mutex structure. | ||
116 | * | ||
117 | * \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.) | ||
118 | * \return COREMUTEX_OK (mutex successfully locked.) | ||
119 | * | ||
120 | * \see imx_sema4_mutex_unlock | ||
121 | */ | ||
122 | int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr) | ||
123 | { | ||
124 | int ret = 0, i = mutex_ptr->gate_num; | ||
125 | |||
126 | if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) | ||
127 | return -EINVAL; | ||
128 | |||
129 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
130 | mutex_ptr->gate_val &= SEMA4_GATE_MASK; | ||
131 | /* Check to see if this core already own it */ | ||
132 | if (mutex_ptr->gate_val == SEMA4_A9_LOCK) { | ||
133 | /* return -EBUSY, invoker should be in sleep, and re-lock ag */ | ||
134 | pr_err("%s -> %s %d already locked, wait! num %d val %d.\n", | ||
135 | __FILE__, __func__, __LINE__, | ||
136 | i, mutex_ptr->gate_val); | ||
137 | ret = -EBUSY; | ||
138 | goto out; | ||
139 | } else { | ||
140 | /* try to lock the mutex */ | ||
141 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
142 | mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); | ||
143 | mutex_ptr->gate_val |= SEMA4_A9_LOCK; | ||
144 | writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i); | ||
145 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
146 | mutex_ptr->gate_val &= SEMA4_GATE_MASK; | ||
147 | /* double check the mutex is locked, otherwise, return -EBUSY */ | ||
148 | if (mutex_ptr->gate_val != SEMA4_A9_LOCK) { | ||
149 | pr_debug("wait-locked num %d val %d.\n", | ||
150 | i, mutex_ptr->gate_val); | ||
151 | ret = -EBUSY; | ||
152 | } | ||
153 | } | ||
154 | out: | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | /* ! | ||
159 | * \brief Try to lock the core mutex. | ||
160 | * | ||
161 | * This function attempts to lock a mutex. If the mutex is successfully locked | ||
162 | * for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already | ||
163 | * locked by another task, the function does not block but rather returns | ||
164 | * negative immediately. | ||
165 | * | ||
166 | * \param[in] mutex_ptr Pointer to core_mutex structure. | ||
167 | * | ||
168 | * \return SEMA4_A9_LOCK (mutex successfully locked.) | ||
169 | * \return negative (mutex not locked.) | ||
170 | * | ||
171 | */ | ||
172 | int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr) | ||
173 | { | ||
174 | int ret = 0; | ||
175 | |||
176 | ret = _imx_sema4_mutex_lock(mutex_ptr); | ||
177 | if (ret == 0) | ||
178 | return SEMA4_A9_LOCK; | ||
179 | else | ||
180 | return ret; | ||
181 | } | ||
182 | EXPORT_SYMBOL(imx_sema4_mutex_trylock); | ||
183 | |||
184 | /*! | ||
185 | * \brief Invoke _imx_sema4_mutex_lock to lock the mutex. | ||
186 | * | ||
187 | * This function attempts to lock a mutex. If the mutex is already locked | ||
188 | * by another task the function, sleep itself and schedule out. | ||
189 | * Wait until it is possible to lock the mutex. | ||
190 | * | ||
191 | * Invoker should add its own wait queue into the wait queue header of the | ||
192 | * required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by | ||
193 | * schedule() when the lock is failed. Re-try to lock the semaphore when | ||
194 | * it is woke up by the sema4 isr. | ||
195 | * | ||
196 | * \param[in] mutex_ptr Pointer to mutex structure. | ||
197 | * | ||
198 | * \return SEMA4_A9_LOCK (mutex successfully locked.) | ||
199 | * | ||
200 | * \see imx_sema4_mutex_unlock | ||
201 | */ | ||
202 | int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr) | ||
203 | { | ||
204 | int ret = 0; | ||
205 | unsigned long flags; | ||
206 | unsigned long timeout_j; /* jiffies */ | ||
207 | |||
208 | spin_lock_irqsave(&imx6_sema4->lock, flags); | ||
209 | ret = _imx_sema4_mutex_lock(mutex_ptr); | ||
210 | spin_unlock_irqrestore(&imx6_sema4->lock, flags); | ||
211 | while (-EBUSY == ret) { | ||
212 | if (MCC_SHMEM_SEMAPHORE_NUMBER == mutex_ptr->gate_num) { | ||
213 | timeout_j = msecs_to_jiffies(1000); | ||
214 | wait_event_timeout(mutex_ptr->wait_q, | ||
215 | mutex_ptr->gate_val == 0, timeout_j); | ||
216 | pr_debug("wake up val %d.\n", mutex_ptr->gate_val); | ||
217 | } | ||
218 | spin_lock_irqsave(&imx6_sema4->lock, flags); | ||
219 | ret = _imx_sema4_mutex_lock(mutex_ptr); | ||
220 | spin_unlock_irqrestore(&imx6_sema4->lock, flags); | ||
221 | if (ret == 0) | ||
222 | break; | ||
223 | } | ||
224 | |||
225 | return ret; | ||
226 | } | ||
227 | EXPORT_SYMBOL(imx_sema4_mutex_lock); | ||
228 | |||
229 | /*! | ||
230 | * \brief Unlock the mutex. | ||
231 | * | ||
232 | * This function unlocks the specified mutex. | ||
233 | * | ||
234 | * \param[in] mutex_ptr Pointer to mutex structure. | ||
235 | * | ||
236 | * \return -EINVAL (Wrong pointer to the mutex structure provided.) | ||
237 | * \return -EINVAL (This mutex has not been locked by this core.) | ||
238 | * \return 0 (mutex successfully unlocked.) | ||
239 | * | ||
240 | * \see imx_sema4_mutex_lock | ||
241 | */ | ||
242 | int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr) | ||
243 | { | ||
244 | int ret = 0, i = mutex_ptr->gate_num; | ||
245 | |||
246 | if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID)) | ||
247 | return -EINVAL; | ||
248 | |||
249 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
250 | mutex_ptr->gate_val &= SEMA4_GATE_MASK; | ||
251 | /* make sure it is locked by this core */ | ||
252 | if (mutex_ptr->gate_val != SEMA4_A9_LOCK) { | ||
253 | pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__); | ||
254 | ret = -EINVAL; | ||
255 | goto out; | ||
256 | } | ||
257 | /* unlock it */ | ||
258 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
259 | mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); | ||
260 | writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i); | ||
261 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
262 | mutex_ptr->gate_val &= SEMA4_GATE_MASK; | ||
263 | /* make sure it is locked by this core */ | ||
264 | if (mutex_ptr->gate_val != SEMA4_UNLOCK) | ||
265 | pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__); | ||
266 | |||
267 | out: | ||
268 | return ret; | ||
269 | } | ||
270 | EXPORT_SYMBOL(imx_sema4_mutex_unlock); | ||
271 | |||
272 | /* | ||
273 | * isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting | ||
274 | * for locking semaphore. | ||
275 | * FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet! | ||
276 | */ | ||
277 | static irqreturn_t imx_sema4_isr(int irq, void *dev_id) | ||
278 | { | ||
279 | int i; | ||
280 | struct imx_sema4_mutex *mutex_ptr; | ||
281 | u32 mask; | ||
282 | struct imx_sema4_mutex_device *imx6_sema4 = dev_id; | ||
283 | |||
284 | imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF); | ||
285 | for (i = 0; i < SEMA4_NUM_GATES; i++) { | ||
286 | mask = idx_sema4[i]; | ||
287 | if ((imx6_sema4->cpntf_val) & mask) { | ||
288 | mutex_ptr = imx6_sema4->mutex_ptr[i]; | ||
289 | /* | ||
290 | * An interrupt is pending on this mutex, the only way | ||
291 | * to clear it is to lock it (either by this core or | ||
292 | * another). | ||
293 | */ | ||
294 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
295 | mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); | ||
296 | mutex_ptr->gate_val |= SEMA4_A9_LOCK; | ||
297 | writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i); | ||
298 | mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i); | ||
299 | mutex_ptr->gate_val &= SEMA4_GATE_MASK; | ||
300 | if (mutex_ptr->gate_val == SEMA4_A9_LOCK) { | ||
301 | /* | ||
302 | * wake up the wait queue, whatever there | ||
303 | * are wait task or not. | ||
304 | * NOTE: check gate is locted or not in | ||
305 | * sema4_lock func by wait task. | ||
306 | */ | ||
307 | mutex_ptr->gate_val = | ||
308 | readb(imx6_sema4->ioaddr + i); | ||
309 | mutex_ptr->gate_val &= (~SEMA4_GATE_MASK); | ||
310 | mutex_ptr->gate_val |= SEMA4_UNLOCK; | ||
311 | |||
312 | writeb(mutex_ptr->gate_val, | ||
313 | imx6_sema4->ioaddr + i); | ||
314 | wake_up(&mutex_ptr->wait_q); | ||
315 | } else { | ||
316 | pr_err("can't lock gate%d re-do it! %s->%s\n", | ||
317 | i, __FILE__, __func__); | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | return IRQ_HANDLED; | ||
323 | } | ||
324 | |||
325 | static const struct of_device_id imx_sema4_dt_ids[] = { | ||
326 | { .compatible = "fsl,imx6sx-sema4", }, | ||
327 | { /* sentinel */ } | ||
328 | }; | ||
329 | MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids); | ||
330 | |||
331 | static int imx_sema4_probe(struct platform_device *pdev) | ||
332 | { | ||
333 | struct resource *res; | ||
334 | int ret; | ||
335 | |||
336 | imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL); | ||
337 | if (!imx6_sema4) | ||
338 | return -ENOMEM; | ||
339 | |||
340 | imx6_sema4->dev = &pdev->dev; | ||
341 | imx6_sema4->cpine_val = 0; | ||
342 | |||
343 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
344 | if (IS_ERR(res)) { | ||
345 | dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n"); | ||
346 | ret = -ENODEV; | ||
347 | goto err; | ||
348 | } | ||
349 | |||
350 | imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res); | ||
351 | if (IS_ERR(imx6_sema4->ioaddr)) { | ||
352 | ret = PTR_ERR(imx6_sema4->ioaddr); | ||
353 | goto err; | ||
354 | } | ||
355 | |||
356 | imx6_sema4->irq = platform_get_irq(pdev, 0); | ||
357 | if (!imx6_sema4->irq) { | ||
358 | dev_err(&pdev->dev, "failed to get irq\n"); | ||
359 | ret = -ENODEV; | ||
360 | goto err; | ||
361 | } | ||
362 | |||
363 | ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr, | ||
364 | IRQF_SHARED, "imx6sx-sema4", imx6_sema4); | ||
365 | if (ret) { | ||
366 | dev_err(&pdev->dev, "failed to request imx sema4 irq\n"); | ||
367 | ret = -ENODEV; | ||
368 | goto err; | ||
369 | } | ||
370 | |||
371 | platform_set_drvdata(pdev, imx6_sema4); | ||
372 | |||
373 | err: | ||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | static int imx_sema4_remove(struct platform_device *pdev) | ||
378 | { | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static struct platform_driver imx_sema4_driver = { | ||
383 | .driver = { | ||
384 | .owner = THIS_MODULE, | ||
385 | .name = "imx-sema4", | ||
386 | .of_match_table = imx_sema4_dt_ids, | ||
387 | }, | ||
388 | .probe = imx_sema4_probe, | ||
389 | .remove = imx_sema4_remove, | ||
390 | }; | ||
391 | |||
392 | static int __init imx_sema4_init(void) | ||
393 | { | ||
394 | int ret; | ||
395 | |||
396 | ret = platform_driver_register(&imx_sema4_driver); | ||
397 | if (ret) | ||
398 | pr_err("Unable to initialize sema4 driver\n"); | ||
399 | else | ||
400 | pr_info("imx sema4 driver is registered.\n"); | ||
401 | |||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | static void __exit imx_sema4_exit(void) | ||
406 | { | ||
407 | pr_info("imx sema4 driver is unregistered.\n"); | ||
408 | platform_driver_unregister(&imx_sema4_driver); | ||
409 | } | ||
410 | |||
411 | module_exit(imx_sema4_exit); | ||
412 | module_init(imx_sema4_init); | ||
413 | |||
414 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
415 | MODULE_DESCRIPTION("IMX SEMA4 driver"); | ||
416 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/imx_sema4.h b/include/linux/imx_sema4.h new file mode 100644 index 000000000000..51a25e1b51bc --- /dev/null +++ b/include/linux/imx_sema4.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef __LINUX_IMX_SEMA4_H__ | ||
10 | #define __LINUX_IMX_SEMA4_H__ | ||
11 | |||
12 | /* semaphore number */ | ||
13 | #define MCC_SHMEM_SEMAPHORE_NUMBER (1) | ||
14 | #define MCC_PRINTF_SEMAPHORE_NUMBER (2) | ||
15 | #define MCC_I2C_SEMAPHORE_NUMBER (3) | ||
16 | #define MCC_RESERVED1_SEMAPHORE_NUMBER (4) | ||
17 | #define MCC_RESERVED2_SEMAPHORE_NUMBER (5) | ||
18 | |||
19 | #define SEMA4_NUM_DEVICES 1 | ||
20 | #define SEMA4_NUM_GATES 16 | ||
21 | |||
22 | #define SEMA4_UNLOCK 0x00 | ||
23 | #define SEMA4_A9_LOCK 0x01 | ||
24 | #define SEMA4_GATE_MASK 0x03 | ||
25 | |||
26 | #define CORE_MUTEX_VALID (('c'<<24)|('m'<<24)|('t'<<24)|'x') | ||
27 | |||
28 | /* | ||
29 | * The enumerates | ||
30 | */ | ||
31 | enum { | ||
32 | /* sema4 registers offset */ | ||
33 | SEMA4_CP0INE = 0x40, | ||
34 | SEMA4_CP1INE = 0x48, | ||
35 | SEMA4_CP0NTF = 0x80, | ||
36 | SEMA4_CP1NTF = 0x88, | ||
37 | }; | ||
38 | |||
39 | static const unsigned int idx_sema4[16] = { | ||
40 | 1 << 7, 1 << 6, 1 << 5, 1 << 4, | ||
41 | 1 << 3, 1 << 2, 1 << 1, 1 << 0, | ||
42 | 1 << 15, 1 << 14, 1 << 13, 1 << 12, | ||
43 | 1 << 11, 1 << 10, 1 << 9, 1 << 8, | ||
44 | }; | ||
45 | |||
46 | struct imx_sema4_mutex { | ||
47 | u32 valid; | ||
48 | u32 gate_num; | ||
49 | unsigned char gate_val; | ||
50 | wait_queue_head_t wait_q; | ||
51 | }; | ||
52 | |||
53 | struct imx_sema4_mutex_device { | ||
54 | struct device *dev; | ||
55 | u16 cpntf_val; | ||
56 | u16 cpine_val; | ||
57 | void __iomem *ioaddr; /* Mapped address */ | ||
58 | spinlock_t lock; /* Mutex */ | ||
59 | int irq; | ||
60 | |||
61 | u16 alloced; | ||
62 | struct imx_sema4_mutex *mutex_ptr[16]; | ||
63 | }; | ||
64 | |||
65 | struct imx_sema4_mutex * | ||
66 | imx_sema4_mutex_create(u32 dev_num, u32 mutex_num); | ||
67 | int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr); | ||
68 | int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr); | ||
69 | int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr); | ||
70 | int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr); | ||
71 | #endif /* __LINUX_IMX_SEMA4_H__ */ | ||