1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/mfd/ab3100_otp.c
5 * Copyright (C) 2007-2009 ST-Ericsson AB
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/abx500.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 * @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
59 struct dentry
*debugfs
;
62 static int __init
ab3100_otp_read(struct ab3100_otp
*otp
)
68 err
= abx500_get_register_interruptible(otp
->dev
, 0,
71 dev_err(otp
->dev
, "unable to read OTPP register\n");
75 err
= abx500_get_register_page_interruptible(otp
->dev
, 0,
76 AB3100_OTP0
, otpval
, 8);
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.
98 #ifdef CONFIG_DEBUG_FS
99 static int ab3100_show_otp(struct seq_file
*s
, void *v
)
101 struct ab3100_otp
*otp
= s
->private;
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
);
113 static int ab3100_otp_open(struct inode
*inode
, struct file
*file
)
115 return single_open(file
, ab3100_show_otp
, inode
->i_private
);
118 static const struct file_operations ab3100_otp_operations
= {
119 .open
= ab3100_otp_open
,
122 .release
= single_release
,
125 static void __init
ab3100_otp_init_debugfs(struct device
*dev
,
126 struct ab3100_otp
*otp
)
128 otp
->debugfs
= debugfs_create_file("ab3100_otp", S_IFREG
| S_IRUGO
,
129 NULL
, otp
, &ab3100_otp_operations
);
132 static void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
134 debugfs_remove(otp
->debugfs
);
137 /* Compile this out if debugfs not selected */
138 static inline void __init
ab3100_otp_init_debugfs(struct device
*dev
,
139 struct ab3100_otp
*otp
)
143 static inline void __exit
ab3100_otp_exit_debugfs(struct ab3100_otp
*otp
)
148 #define SHOW_AB3100_ATTR(name) \
149 static ssize_t ab3100_otp_##name##_show(struct device *dev, \
150 struct device_attribute *attr, \
153 struct ab3100_otp *otp = dev_get_drvdata(dev); \
154 return sprintf(buf, "%u\n", otp->name); \
157 SHOW_AB3100_ATTR(locked
)
158 SHOW_AB3100_ATTR(freq
)
159 SHOW_AB3100_ATTR(paf
)
160 SHOW_AB3100_ATTR(imeich
)
161 SHOW_AB3100_ATTR(cid
)
162 SHOW_AB3100_ATTR(fac
)
163 SHOW_AB3100_ATTR(tac
)
164 SHOW_AB3100_ATTR(svn
)
166 static struct device_attribute ab3100_otp_attrs
[] = {
167 __ATTR(locked
, S_IRUGO
, ab3100_otp_locked_show
, NULL
),
168 __ATTR(freq
, S_IRUGO
, ab3100_otp_freq_show
, NULL
),
169 __ATTR(paf
, S_IRUGO
, ab3100_otp_paf_show
, NULL
),
170 __ATTR(imeich
, S_IRUGO
, ab3100_otp_imeich_show
, NULL
),
171 __ATTR(cid
, S_IRUGO
, ab3100_otp_cid_show
, NULL
),
172 __ATTR(fac
, S_IRUGO
, ab3100_otp_fac_show
, NULL
),
173 __ATTR(tac
, S_IRUGO
, ab3100_otp_tac_show
, NULL
),
174 __ATTR(svn
, S_IRUGO
, ab3100_otp_svn_show
, NULL
),
177 static int __init
ab3100_otp_probe(struct platform_device
*pdev
)
179 struct ab3100_otp
*otp
;
183 otp
= devm_kzalloc(&pdev
->dev
, sizeof(struct ab3100_otp
), GFP_KERNEL
);
187 otp
->dev
= &pdev
->dev
;
189 /* Replace platform data coming in with a local struct */
190 platform_set_drvdata(pdev
, otp
);
192 err
= ab3100_otp_read(otp
);
196 dev_info(&pdev
->dev
, "AB3100 OTP readout registered\n");
199 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++) {
200 err
= device_create_file(&pdev
->dev
,
201 &ab3100_otp_attrs
[i
]);
206 /* debugfs entries */
207 ab3100_otp_init_debugfs(&pdev
->dev
, otp
);
213 device_remove_file(&pdev
->dev
, &ab3100_otp_attrs
[i
]);
217 static int __exit
ab3100_otp_remove(struct platform_device
*pdev
)
219 struct ab3100_otp
*otp
= platform_get_drvdata(pdev
);
222 for (i
= 0; i
< ARRAY_SIZE(ab3100_otp_attrs
); i
++)
223 device_remove_file(&pdev
->dev
,
224 &ab3100_otp_attrs
[i
]);
225 ab3100_otp_exit_debugfs(otp
);
229 static struct platform_driver ab3100_otp_driver
= {
231 .name
= "ab3100-otp",
233 .remove
= __exit_p(ab3100_otp_remove
),
236 module_platform_driver_probe(ab3100_otp_driver
, ab3100_otp_probe
);
238 MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
239 MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
240 MODULE_LICENSE("GPL");