2 * drivers/mfd/ab3100_otp.c
4 * Copyright (C) 2007-2009 ST-Ericsson AB
5 * License terms: GNU General Public License (GPL) version 2
6 * Driver to read out OTP from the AB3100 Mixed-signal circuit
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
13 #include <linux/init.h>
14 #include <linux/platform_device.h>
15 #include <linux/mfd/ab3100.h>
16 #include <linux/debugfs.h>
17 #include <linux/seq_file.h>
19 /* The OTP registers */
20 #define AB3100_OTP0 0xb0
21 #define AB3100_OTP1 0xb1
22 #define AB3100_OTP2 0xb2
23 #define AB3100_OTP3 0xb3
24 #define AB3100_OTP4 0xb4
25 #define AB3100_OTP5 0xb5
26 #define AB3100_OTP6 0xb6
27 #define AB3100_OTP7 0xb7
28 #define AB3100_OTPP 0xbf
32 * @dev containing device
33 * @ab3100 a pointer to the parent ab3100 device struct
34 * @locked whether the OTP is locked, after locking, no more bits
35 * can be changed but before locking it is still possible
36 * to change bits from 1->0.
37 * @freq clocking frequency for the OTP, this frequency is either
39 * @paf product activation flag, indicates whether this is a real
40 * product (paf true) or a lab board etc (paf false)
41 * @imeich if this is set it is possible to override the
42 * IMEI number found in the tac, fac and svn fields with
45 * @tac type allocation code of the IMEI
46 * @fac final assembly code of the IMEI
47 * @svn software version number of the IMEI
48 * @debugfs a debugfs file used when dumping to file
52 struct ab3100
*ab3100
;
61 struct dentry
*debugfs
;
64 static int __init
ab3100_otp_read(struct ab3100_otp
*otp
)
66 struct ab3100
*ab
= otp
->ab3100
;
71 err
= ab3100_get_register_interruptible(ab
, AB3100_OTPP
, &otpp
);
73 dev_err(otp
->dev
, "unable to read OTPP register\n");
77 err
= ab3100_get_register_page_interruptible(ab
, AB3100_OTP0
,
80 dev_err(otp
->dev
, "unable to read OTP register page\n");
84 /* Cache OTP properties, they never change by nature */
85 otp
->locked
= (otpp
& 0x80);
86 otp
->freq
= (otpp
& 0x40) ? 32768 : 34100;
87 otp
->paf
= (otpval
[1] & 0x80);
88 otp
->imeich
= (otpval
[1] & 0x40);
89 otp
->cid
= ((otpval
[1] << 8) | otpval
[0]) & 0x3fff;
90 otp
->tac
= ((otpval
[4] & 0x0f) << 16) | (otpval
[3] << 8) | otpval
[2];
91 otp
->fac
= ((otpval
[5] & 0x0f) << 4) | (otpval
[4] >> 4);
92 otp
->svn
= (otpval
[7] << 12) | (otpval
[6] << 4) | (otpval
[5] >> 4);
97 * This is a simple debugfs human-readable file that dumps out
98 * the contents of the OTP.
100 #ifdef CONFIG_DEBUG_FS
101 static int ab3100_show_otp(struct seq_file
*s
, void *v
)
103 struct ab3100_otp
*otp
= s
->private;
105 seq_printf(s
, "OTP is %s\n", otp
->locked
? "LOCKED" : "UNLOCKED");
106 seq_printf(s
, "OTP clock switch startup is %uHz\n", otp
->freq
);
107 seq_printf(s
, "PAF is %s\n", otp
->paf
? "SET" : "NOT SET");
108 seq_printf(s
, "IMEI is %s\n", otp
->imeich
?
109 "CHANGEABLE" : "NOT CHANGEABLE");
110 seq_printf(s
, "CID: 0x%04x (decimal: %d)\n", otp
->cid
, otp
->cid
);
111 seq_printf(s
, "IMEI: %u-%u-%u\n", otp
->tac
, otp
->fac
, otp
->svn
);
115 static int ab3100_otp_open(struct inode
*inode
, struct file
*file
)
117 return single_open(file
, ab3100_show_otp
, inode
->i_private
);
120 static const struct file_operations ab3100_otp_operations
= {
121 .open
= ab3100_otp_open
,
124 .release
= single_release
,
127 static int __init
ab3100_otp_init_debugfs(struct device
*dev
,
128 struct ab3100_otp
*otp
)
130 otp
->debugfs
= debugfs_create_file("ab3100_otp", S_IFREG
| S_IRUGO
,
132 &ab3100_otp_operations
);
134 dev_err(dev
, "AB3100 debugfs OTP file registration failed!\n");
140 static void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
142 debugfs_remove(otp
->debugfs
);
145 /* Compile this out if debugfs not selected */
146 static inline int __init
ab3100_otp_init_debugfs(struct device
*dev
,
147 struct ab3100_otp
*otp
)
152 static inline void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
157 #define SHOW_AB3100_ATTR(name) \
158 static ssize_t ab3100_otp_##name##_show(struct device *dev, \
159 struct device_attribute *attr, \
162 struct ab3100_otp *otp = dev_get_drvdata(dev); \
163 return sprintf(buf, "%u\n", otp->name); \
166 SHOW_AB3100_ATTR(locked
)
167 SHOW_AB3100_ATTR(freq
)
168 SHOW_AB3100_ATTR(paf
)
169 SHOW_AB3100_ATTR(imeich
)
170 SHOW_AB3100_ATTR(cid
)
171 SHOW_AB3100_ATTR(fac
)
172 SHOW_AB3100_ATTR(tac
)
173 SHOW_AB3100_ATTR(svn
)
175 static struct device_attribute ab3100_otp_attrs
[] = {
176 __ATTR(locked
, S_IRUGO
, ab3100_otp_locked_show
, NULL
),
177 __ATTR(freq
, S_IRUGO
, ab3100_otp_freq_show
, NULL
),
178 __ATTR(paf
, S_IRUGO
, ab3100_otp_paf_show
, NULL
),
179 __ATTR(imeich
, S_IRUGO
, ab3100_otp_imeich_show
, NULL
),
180 __ATTR(cid
, S_IRUGO
, ab3100_otp_cid_show
, NULL
),
181 __ATTR(fac
, S_IRUGO
, ab3100_otp_fac_show
, NULL
),
182 __ATTR(tac
, S_IRUGO
, ab3100_otp_tac_show
, NULL
),
183 __ATTR(svn
, S_IRUGO
, ab3100_otp_svn_show
, NULL
),
186 static int __init
ab3100_otp_probe(struct platform_device
*pdev
)
188 struct ab3100_otp
*otp
;
192 otp
= kzalloc(sizeof(struct ab3100_otp
), GFP_KERNEL
);
194 dev_err(&pdev
->dev
, "could not allocate AB3100 OTP device\n");
197 otp
->dev
= &pdev
->dev
;
199 /* Replace platform data coming in with a local struct */
200 otp
->ab3100
= platform_get_drvdata(pdev
);
201 platform_set_drvdata(pdev
, otp
);
203 err
= ab3100_otp_read(otp
);
207 dev_info(&pdev
->dev
, "AB3100 OTP readout registered\n");
210 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++) {
211 err
= device_create_file(&pdev
->dev
,
212 &ab3100_otp_attrs
[i
]);
217 /* debugfs entries */
218 err
= ab3100_otp_init_debugfs(&pdev
->dev
, otp
);
225 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
226 device_remove_file(&pdev
->dev
,
227 &ab3100_otp_attrs
[i
]);
233 static int __exit
ab3100_otp_remove(struct platform_device
*pdev
)
235 struct ab3100_otp
*otp
= platform_get_drvdata(pdev
);
238 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
239 device_remove_file(&pdev
->dev
,
240 &ab3100_otp_attrs
[i
]);
241 ab3100_otp_exit_debugfs(otp
);
246 static struct platform_driver ab3100_otp_driver
= {
248 .name
= "ab3100-otp",
249 .owner
= THIS_MODULE
,
251 .remove
= __exit_p(ab3100_otp_remove
),
254 static int __init
ab3100_otp_init(void)
256 return platform_driver_probe(&ab3100_otp_driver
,
260 static void __exit
ab3100_otp_exit(void)
262 platform_driver_unregister(&ab3100_otp_driver
);
265 module_init(ab3100_otp_init
);
266 module_exit(ab3100_otp_exit
);
268 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
269 MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
270 MODULE_LICENSE("GPL");