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>
16 #include <linux/seq_file.h>
18 /* The OTP registers */
19 #define AB3100_OTP0 0xb0
20 #define AB3100_OTP1 0xb1
21 #define AB3100_OTP2 0xb2
22 #define AB3100_OTP3 0xb3
23 #define AB3100_OTP4 0xb4
24 #define AB3100_OTP5 0xb5
25 #define AB3100_OTP6 0xb6
26 #define AB3100_OTP7 0xb7
27 #define AB3100_OTPP 0xbf
31 * @dev containing device
32 * @ab3100 a pointer to the parent ab3100 device struct
33 * @locked whether the OTP is locked, after locking, no more bits
34 * can be changed but before locking it is still possible
35 * to change bits from 1->0.
36 * @freq clocking frequency for the OTP, this frequency is either
38 * @paf product activation flag, indicates whether this is a real
39 * product (paf true) or a lab board etc (paf false)
40 * @imeich if this is set it is possible to override the
41 * IMEI number found in the tac, fac and svn fields with
44 * @tac type allocation code of the IMEI
45 * @fac final assembly code of the IMEI
46 * @svn software version number of the IMEI
47 * @debugfs a debugfs file used when dumping to file
51 struct ab3100
*ab3100
;
60 struct dentry
*debugfs
;
63 static int __init
ab3100_otp_read(struct ab3100_otp
*otp
)
65 struct ab3100
*ab
= otp
->ab3100
;
70 err
= ab3100_get_register_interruptible(ab
, AB3100_OTPP
, &otpp
);
72 dev_err(otp
->dev
, "unable to read OTPP register\n");
76 err
= ab3100_get_register_page_interruptible(ab
, AB3100_OTP0
,
79 dev_err(otp
->dev
, "unable to read OTP register page\n");
83 /* Cache OTP properties, they never change by nature */
84 otp
->locked
= (otpp
& 0x80);
85 otp
->freq
= (otpp
& 0x40) ? 32768 : 34100;
86 otp
->paf
= (otpval
[1] & 0x80);
87 otp
->imeich
= (otpval
[1] & 0x40);
88 otp
->cid
= ((otpval
[1] << 8) | otpval
[0]) & 0x3fff;
89 otp
->tac
= ((otpval
[4] & 0x0f) << 16) | (otpval
[3] << 8) | otpval
[2];
90 otp
->fac
= ((otpval
[5] & 0x0f) << 4) | (otpval
[4] >> 4);
91 otp
->svn
= (otpval
[7] << 12) | (otpval
[6] << 4) | (otpval
[5] >> 4);
96 * This is a simple debugfs human-readable file that dumps out
97 * the contents of the OTP.
99 #ifdef CONFIG_DEBUG_FS
100 static int ab3100_show_otp(struct seq_file
*s
, void *v
)
102 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_show_otp
, 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");
139 static void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
141 debugfs_remove(otp
->debugfs
);
144 /* Compile this out if debugfs not selected */
145 static inline int __init
ab3100_otp_init_debugfs(struct device
*dev
,
146 struct ab3100_otp
*otp
)
151 static inline void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
156 #define SHOW_AB3100_ATTR(name) \
157 static ssize_t ab3100_otp_##name##_show(struct device *dev, \
158 struct device_attribute *attr, \
161 struct ab3100_otp *otp = dev_get_drvdata(dev); \
162 return sprintf(buf, "%u\n", otp->name); \
165 SHOW_AB3100_ATTR(locked
)
166 SHOW_AB3100_ATTR(freq
)
167 SHOW_AB3100_ATTR(paf
)
168 SHOW_AB3100_ATTR(imeich
)
169 SHOW_AB3100_ATTR(cid
)
170 SHOW_AB3100_ATTR(fac
)
171 SHOW_AB3100_ATTR(tac
)
172 SHOW_AB3100_ATTR(svn
)
174 static struct device_attribute ab3100_otp_attrs
[] = {
175 __ATTR(locked
, S_IRUGO
, ab3100_otp_locked_show
, NULL
),
176 __ATTR(freq
, S_IRUGO
, ab3100_otp_freq_show
, NULL
),
177 __ATTR(paf
, S_IRUGO
, ab3100_otp_paf_show
, NULL
),
178 __ATTR(imeich
, S_IRUGO
, ab3100_otp_imeich_show
, NULL
),
179 __ATTR(cid
, S_IRUGO
, ab3100_otp_cid_show
, NULL
),
180 __ATTR(fac
, S_IRUGO
, ab3100_otp_fac_show
, NULL
),
181 __ATTR(tac
, S_IRUGO
, ab3100_otp_tac_show
, NULL
),
182 __ATTR(svn
, S_IRUGO
, ab3100_otp_svn_show
, NULL
),
185 static int __init
ab3100_otp_probe(struct platform_device
*pdev
)
187 struct ab3100_otp
*otp
;
191 otp
= kzalloc(sizeof(struct ab3100_otp
), GFP_KERNEL
);
193 dev_err(&pdev
->dev
, "could not allocate AB3100 OTP device\n");
196 otp
->dev
= &pdev
->dev
;
198 /* Replace platform data coming in with a local struct */
199 otp
->ab3100
= platform_get_drvdata(pdev
);
200 platform_set_drvdata(pdev
, otp
);
202 err
= ab3100_otp_read(otp
);
206 dev_info(&pdev
->dev
, "AB3100 OTP readout registered\n");
209 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++) {
210 err
= device_create_file(&pdev
->dev
,
211 &ab3100_otp_attrs
[i
]);
216 /* debugfs entries */
217 err
= ab3100_otp_init_debugfs(&pdev
->dev
, otp
);
224 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
225 device_remove_file(&pdev
->dev
,
226 &ab3100_otp_attrs
[i
]);
232 static int __exit
ab3100_otp_remove(struct platform_device
*pdev
)
234 struct ab3100_otp
*otp
= platform_get_drvdata(pdev
);
237 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
238 device_remove_file(&pdev
->dev
,
239 &ab3100_otp_attrs
[i
]);
240 ab3100_otp_exit_debugfs(otp
);
245 static struct platform_driver ab3100_otp_driver
= {
247 .name
= "ab3100-otp",
248 .owner
= THIS_MODULE
,
250 .remove
= __exit_p(ab3100_otp_remove
),
253 static int __init
ab3100_otp_init(void)
255 return platform_driver_probe(&ab3100_otp_driver
,
259 static void __exit
ab3100_otp_exit(void)
261 platform_driver_unregister(&ab3100_otp_driver
);
264 module_init(ab3100_otp_init
);
265 module_exit(ab3100_otp_exit
);
267 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
268 MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
269 MODULE_LICENSE("GPL");