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/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/mfd/ab3100.h>
15 #include <linux/debugfs.h>
17 /* The OTP registers */
18 #define AB3100_OTP0 0xb0
19 #define AB3100_OTP1 0xb1
20 #define AB3100_OTP2 0xb2
21 #define AB3100_OTP3 0xb3
22 #define AB3100_OTP4 0xb4
23 #define AB3100_OTP5 0xb5
24 #define AB3100_OTP6 0xb6
25 #define AB3100_OTP7 0xb7
26 #define AB3100_OTPP 0xbf
30 * @dev containing device
31 * @ab3100 a pointer to the parent ab3100 device struct
32 * @locked whether the OTP is locked, after locking, no more bits
33 * can be changed but before locking it is still possible
34 * to change bits from 1->0.
35 * @freq clocking frequency for the OTP, this frequency is either
37 * @paf product activation flag, indicates whether this is a real
38 * product (paf true) or a lab board etc (paf false)
39 * @imeich if this is set it is possible to override the
40 * IMEI number found in the tac, fac and svn fields with
43 * @tac type allocation code of the IMEI
44 * @fac final assembly code of the IMEI
45 * @svn software version number of the IMEI
46 * @debugfs a debugfs file used when dumping to file
50 struct ab3100
*ab3100
;
59 struct dentry
*debugfs
;
62 static int __init
ab3100_otp_read(struct ab3100_otp
*otp
)
64 struct ab3100
*ab
= otp
->ab3100
;
69 err
= ab3100_get_register_interruptible(ab
, AB3100_OTPP
, &otpp
);
71 dev_err(otp
->dev
, "unable to read OTPP register\n");
75 err
= ab3100_get_register_page_interruptible(ab
, AB3100_OTP0
,
78 dev_err(otp
->dev
, "unable to read OTP register page\n");
82 /* Cache OTP properties, they never change by nature */
83 otp
->locked
= (otpp
& 0x80);
84 otp
->freq
= (otpp
& 0x40) ? 32768 : 34100;
85 otp
->paf
= (otpval
[1] & 0x80);
86 otp
->imeich
= (otpval
[1] & 0x40);
87 otp
->cid
= ((otpval
[1] << 8) | otpval
[0]) & 0x3fff;
88 otp
->tac
= ((otpval
[4] & 0x0f) << 16) | (otpval
[3] << 8) | otpval
[2];
89 otp
->fac
= ((otpval
[5] & 0x0f) << 4) | (otpval
[4] >> 4);
90 otp
->svn
= (otpval
[7] << 12) | (otpval
[6] << 4) | (otpval
[5] >> 4);
95 * This is a simple debugfs human-readable file that dumps out
96 * the contents of the OTP.
99 static int show_otp(struct seq_file
*s
, void *v
)
101 struct ab3100_otp
*otp
= s
->private;
104 seq_printf(s
, "OTP is %s\n", otp
->locked
? "LOCKED" : "UNLOCKED");
105 seq_printf(s
, "OTP clock switch startup is %uHz\n", otp
->freq
);
106 seq_printf(s
, "PAF is %s\n", otp
->paf
? "SET" : "NOT SET");
107 seq_printf(s
, "IMEI is %s\n", otp
->imeich
?
108 "CHANGEABLE" : "NOT CHANGEABLE");
109 seq_printf(s
, "CID: 0x%04x (decimal: %d)\n", otp
->cid
, otp
->cid
);
110 seq_printf(s
, "IMEI: %u-%u-%u\n", otp
->tac
, otp
->fac
, otp
->svn
);
114 static int ab3100_otp_open(struct inode
*inode
, struct file
*file
)
116 return single_open(file
, ab3100_otp_show
, inode
->i_private
);
119 static const struct file_operations ab3100_otp_operations
= {
120 .open
= ab3100_otp_open
,
123 .release
= single_release
,
126 static int __init
ab3100_otp_init_debugfs(struct device
*dev
,
127 struct ab3100_otp
*otp
)
129 otp
->debugfs
= debugfs_create_file("ab3100_otp", S_IFREG
| S_IRUGO
,
131 &ab3100_otp_operations
);
133 dev_err(dev
, "AB3100 debugfs OTP file registration failed!\n");
138 static void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
140 debugfs_remove_file(otp
->debugfs
);
143 /* Compile this out if debugfs not selected */
144 static inline int __init
ab3100_otp_init_debugfs(struct device
*dev
,
145 struct ab3100_otp
*otp
)
150 static inline void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
155 #define SHOW_AB3100_ATTR(name) \
156 static ssize_t ab3100_otp_##name##_show(struct device *dev, \
157 struct device_attribute *attr, \
160 struct ab3100_otp *otp = dev_get_drvdata(dev); \
161 return sprintf(buf, "%u\n", otp->name); \
164 SHOW_AB3100_ATTR(locked
)
165 SHOW_AB3100_ATTR(freq
)
166 SHOW_AB3100_ATTR(paf
)
167 SHOW_AB3100_ATTR(imeich
)
168 SHOW_AB3100_ATTR(cid
)
169 SHOW_AB3100_ATTR(fac
)
170 SHOW_AB3100_ATTR(tac
)
171 SHOW_AB3100_ATTR(svn
)
173 static struct device_attribute ab3100_otp_attrs
[] = {
174 __ATTR(locked
, S_IRUGO
, ab3100_otp_locked_show
, NULL
),
175 __ATTR(freq
, S_IRUGO
, ab3100_otp_freq_show
, NULL
),
176 __ATTR(paf
, S_IRUGO
, ab3100_otp_paf_show
, NULL
),
177 __ATTR(imeich
, S_IRUGO
, ab3100_otp_imeich_show
, NULL
),
178 __ATTR(cid
, S_IRUGO
, ab3100_otp_cid_show
, NULL
),
179 __ATTR(fac
, S_IRUGO
, ab3100_otp_fac_show
, NULL
),
180 __ATTR(tac
, S_IRUGO
, ab3100_otp_tac_show
, NULL
),
181 __ATTR(svn
, S_IRUGO
, ab3100_otp_svn_show
, NULL
),
184 static int __init
ab3100_otp_probe(struct platform_device
*pdev
)
186 struct ab3100_otp
*otp
;
190 otp
= kzalloc(sizeof(struct ab3100_otp
), GFP_KERNEL
);
192 dev_err(&pdev
->dev
, "could not allocate AB3100 OTP device\n");
195 otp
->dev
= &pdev
->dev
;
197 /* Replace platform data coming in with a local struct */
198 otp
->ab3100
= platform_get_drvdata(pdev
);
199 platform_set_drvdata(pdev
, otp
);
201 err
= ab3100_otp_read(otp
);
205 dev_info(&pdev
->dev
, "AB3100 OTP readout registered\n");
208 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++) {
209 err
= device_create_file(&pdev
->dev
,
210 &ab3100_otp_attrs
[i
]);
215 /* debugfs entries */
216 err
= ab3100_otp_init_debugfs(&pdev
->dev
, otp
);
223 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
224 device_remove_file(&pdev
->dev
,
225 &ab3100_otp_attrs
[i
]);
231 static int __exit
ab3100_otp_remove(struct platform_device
*pdev
)
233 struct ab3100_otp
*otp
= platform_get_drvdata(pdev
);
236 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
237 device_remove_file(&pdev
->dev
,
238 &ab3100_otp_attrs
[i
]);
239 ab3100_otp_exit_debugfs(otp
);
244 static struct platform_driver ab3100_otp_driver
= {
246 .name
= "ab3100-otp",
247 .owner
= THIS_MODULE
,
249 .remove
= __exit_p(ab3100_otp_remove
),
252 static int __init
ab3100_otp_init(void)
254 return platform_driver_probe(&ab3100_otp_driver
,
258 static void __exit
ab3100_otp_exit(void)
260 platform_driver_unregister(&ab3100_otp_driver
);
263 module_init(ab3100_otp_init
);
264 module_exit(ab3100_otp_exit
);
266 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
267 MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
268 MODULE_LICENSE("GPL");