ab3100-otp.c revision fa661258a27aa74aaf741882053d195291cefb75
1/*
2 * drivers/mfd/ab3100_otp.c
3 *
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>
8 */
9
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/abx500.h>
16#include <linux/debugfs.h>
17#include <linux/seq_file.h>
18
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
29
30/**
31 * struct ab3100_otp
32 * @dev containing device
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
37 *       32768Hz or 1MHz/30
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
42 *       (secured) software
43 * @cid customer ID
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
48 */
49struct ab3100_otp {
50	struct device *dev;
51	bool locked;
52	u32 freq;
53	bool paf;
54	bool imeich;
55	u16 cid:14;
56	u32 tac:20;
57	u8 fac;
58	u32 svn:20;
59	struct dentry *debugfs;
60};
61
62static int __init ab3100_otp_read(struct ab3100_otp *otp)
63{
64	u8 otpval[8];
65	u8 otpp;
66	int err;
67
68	err = abx500_get_register_interruptible(otp->dev, 0,
69		AB3100_OTPP, &otpp);
70	if (err) {
71		dev_err(otp->dev, "unable to read OTPP register\n");
72		return err;
73	}
74
75	err = abx500_get_register_page_interruptible(otp->dev, 0,
76		AB3100_OTP0, otpval, 8);
77	if (err) {
78		dev_err(otp->dev, "unable to read OTP register page\n");
79		return err;
80	}
81
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);
91	return 0;
92}
93
94/*
95 * This is a simple debugfs human-readable file that dumps out
96 * the contents of the OTP.
97 */
98#ifdef CONFIG_DEBUG_FS
99static int ab3100_show_otp(struct seq_file *s, void *v)
100{
101	struct ab3100_otp *otp = s->private;
102
103	seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED");
104	seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq);
105	seq_printf(s, "PAF is %s\n", otp->paf ? "SET" : "NOT SET");
106	seq_printf(s, "IMEI is %s\n", otp->imeich ?
107		   "CHANGEABLE" : "NOT CHANGEABLE");
108	seq_printf(s, "CID: 0x%04x (decimal: %d)\n", otp->cid, otp->cid);
109	seq_printf(s, "IMEI: %u-%u-%u\n", otp->tac, otp->fac, otp->svn);
110	return 0;
111}
112
113static int ab3100_otp_open(struct inode *inode, struct file *file)
114{
115	return single_open(file, ab3100_show_otp, inode->i_private);
116}
117
118static const struct file_operations ab3100_otp_operations = {
119	.open		= ab3100_otp_open,
120	.read		= seq_read,
121	.llseek		= seq_lseek,
122	.release	= single_release,
123};
124
125static int __init ab3100_otp_init_debugfs(struct device *dev,
126					  struct ab3100_otp *otp)
127{
128	otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO,
129					   NULL, otp,
130					   &ab3100_otp_operations);
131	if (!otp->debugfs) {
132		dev_err(dev, "AB3100 debugfs OTP file registration failed!\n");
133		return -ENOENT;
134	}
135	return 0;
136}
137
138static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
139{
140	debugfs_remove(otp->debugfs);
141}
142#else
143/* Compile this out if debugfs not selected */
144static inline int __init ab3100_otp_init_debugfs(struct device *dev,
145						 struct ab3100_otp *otp)
146{
147	return 0;
148}
149
150static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
151{
152}
153#endif
154
155#define SHOW_AB3100_ATTR(name) \
156static ssize_t ab3100_otp_##name##_show(struct device *dev, \
157			       struct device_attribute *attr, \
158			       char *buf) \
159{\
160	struct ab3100_otp *otp = dev_get_drvdata(dev); \
161	return sprintf(buf, "%u\n", otp->name); \
162}
163
164SHOW_AB3100_ATTR(locked)
165SHOW_AB3100_ATTR(freq)
166SHOW_AB3100_ATTR(paf)
167SHOW_AB3100_ATTR(imeich)
168SHOW_AB3100_ATTR(cid)
169SHOW_AB3100_ATTR(fac)
170SHOW_AB3100_ATTR(tac)
171SHOW_AB3100_ATTR(svn)
172
173static 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),
182};
183
184static int __init ab3100_otp_probe(struct platform_device *pdev)
185{
186	struct ab3100_otp *otp;
187	int err = 0;
188	int i;
189
190	otp = kzalloc(sizeof(struct ab3100_otp), GFP_KERNEL);
191	if (!otp) {
192		dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n");
193		return -ENOMEM;
194	}
195	otp->dev = &pdev->dev;
196
197	/* Replace platform data coming in with a local struct */
198	platform_set_drvdata(pdev, otp);
199
200	err = ab3100_otp_read(otp);
201	if (err)
202		return err;
203
204	dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
205
206	/* sysfs entries */
207	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) {
208		err = device_create_file(&pdev->dev,
209					 &ab3100_otp_attrs[i]);
210		if (err)
211			goto out_no_sysfs;
212	}
213
214	/* debugfs entries */
215	err = ab3100_otp_init_debugfs(&pdev->dev, otp);
216	if (err)
217		goto out_no_debugfs;
218
219	return 0;
220
221out_no_sysfs:
222	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
223		device_remove_file(&pdev->dev,
224				   &ab3100_otp_attrs[i]);
225out_no_debugfs:
226	kfree(otp);
227	return err;
228}
229
230static int __exit ab3100_otp_remove(struct platform_device *pdev)
231{
232	struct ab3100_otp *otp = platform_get_drvdata(pdev);
233	int i;
234
235	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
236		device_remove_file(&pdev->dev,
237				   &ab3100_otp_attrs[i]);
238	ab3100_otp_exit_debugfs(otp);
239	kfree(otp);
240	return 0;
241}
242
243static struct platform_driver ab3100_otp_driver = {
244	.driver = {
245		.name = "ab3100-otp",
246		.owner = THIS_MODULE,
247	},
248	.remove	 = __exit_p(ab3100_otp_remove),
249};
250
251static int __init ab3100_otp_init(void)
252{
253	return platform_driver_probe(&ab3100_otp_driver,
254				     ab3100_otp_probe);
255}
256
257static void __exit ab3100_otp_exit(void)
258{
259	platform_driver_unregister(&ab3100_otp_driver);
260}
261
262module_init(ab3100_otp_init);
263module_exit(ab3100_otp_exit);
264
265MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
266MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
267MODULE_LICENSE("GPL");
268