diff options
author | Shawn Guo <shawn.guo@freescale.com> | 2011-01-14 10:11:23 -0500 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-01-21 05:36:49 -0500 |
commit | 67f43086a24b77a82724855141a5b7a4d72549bd (patch) | |
tree | b859152193a7ff7f9e568cbab2c835a4b9c5237d /arch/arm/mach-mxs/ocotp.c | |
parent | bb58b3e8b18c542f30f898fff82f7ce58a4bdf7a (diff) |
ARM: mxs: add ocotp read function
Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-mxs/ocotp.c')
-rw-r--r-- | arch/arm/mach-mxs/ocotp.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c new file mode 100644 index 000000000000..65157a35dbba --- /dev/null +++ b/arch/arm/mach-mxs/ocotp.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved. | ||
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 as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/mutex.h> | ||
18 | |||
19 | #include <mach/mxs.h> | ||
20 | |||
21 | #define OCOTP_WORD_OFFSET 0x20 | ||
22 | #define OCOTP_WORD_COUNT 0x20 | ||
23 | |||
24 | #define BM_OCOTP_CTRL_BUSY (1 << 8) | ||
25 | #define BM_OCOTP_CTRL_ERROR (1 << 9) | ||
26 | #define BM_OCOTP_CTRL_RD_BANK_OPEN (1 << 12) | ||
27 | |||
28 | static DEFINE_MUTEX(ocotp_mutex); | ||
29 | static u32 ocotp_words[OCOTP_WORD_COUNT]; | ||
30 | |||
31 | const u32 *mxs_get_ocotp(void) | ||
32 | { | ||
33 | void __iomem *ocotp_base = MXS_IO_ADDRESS(MXS_OCOTP_BASE_ADDR); | ||
34 | int timeout = 0x400; | ||
35 | size_t i; | ||
36 | static int once = 0; | ||
37 | |||
38 | if (once) | ||
39 | return ocotp_words; | ||
40 | |||
41 | mutex_lock(&ocotp_mutex); | ||
42 | |||
43 | /* | ||
44 | * clk_enable(hbus_clk) for ocotp can be skipped | ||
45 | * as it must be on when system is running. | ||
46 | */ | ||
47 | |||
48 | /* try to clear ERROR bit */ | ||
49 | __mxs_clrl(BM_OCOTP_CTRL_ERROR, ocotp_base); | ||
50 | |||
51 | /* check both BUSY and ERROR cleared */ | ||
52 | while ((__raw_readl(ocotp_base) & | ||
53 | (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR)) && --timeout) | ||
54 | cpu_relax(); | ||
55 | |||
56 | if (unlikely(!timeout)) | ||
57 | goto error_unlock; | ||
58 | |||
59 | /* open OCOTP banks for read */ | ||
60 | __mxs_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); | ||
61 | |||
62 | /* approximately wait 32 hclk cycles */ | ||
63 | udelay(1); | ||
64 | |||
65 | /* poll BUSY bit becoming cleared */ | ||
66 | timeout = 0x400; | ||
67 | while ((__raw_readl(ocotp_base) & BM_OCOTP_CTRL_BUSY) && --timeout) | ||
68 | cpu_relax(); | ||
69 | |||
70 | if (unlikely(!timeout)) | ||
71 | goto error_unlock; | ||
72 | |||
73 | for (i = 0; i < OCOTP_WORD_COUNT; i++) | ||
74 | ocotp_words[i] = __raw_readl(ocotp_base + OCOTP_WORD_OFFSET + | ||
75 | i * 0x10); | ||
76 | |||
77 | /* close banks for power saving */ | ||
78 | __mxs_clrl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); | ||
79 | |||
80 | once = 1; | ||
81 | |||
82 | mutex_unlock(&ocotp_mutex); | ||
83 | |||
84 | return ocotp_words; | ||
85 | |||
86 | error_unlock: | ||
87 | mutex_unlock(&ocotp_mutex); | ||
88 | pr_err("%s: timeout in reading OCOTP\n", __func__); | ||
89 | return NULL; | ||
90 | } | ||