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