1 /* 2 * wm831x-otp.c -- OTP for Wolfson WM831x PMICs 3 * 4 * Copyright 2009 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/i2c.h> 18 #include <linux/bcd.h> 19 #include <linux/delay.h> 20 #include <linux/mfd/core.h> 21 #include <linux/random.h> 22 23 #include <linux/mfd/wm831x/core.h> 24 #include <linux/mfd/wm831x/otp.h> 25 26 /* In bytes */ 27 #define WM831X_UNIQUE_ID_LEN 16 28 29 /* Read the unique ID from the chip into id */ 30 static int wm831x_unique_id_read(struct wm831x *wm831x, char *id) 31 { 32 int i, val; 33 34 for (i = 0; i < WM831X_UNIQUE_ID_LEN / 2; i++) { 35 val = wm831x_reg_read(wm831x, WM831X_UNIQUE_ID_1 + i); 36 if (val < 0) 37 return val; 38 39 id[i * 2] = (val >> 8) & 0xff; 40 id[(i * 2) + 1] = val & 0xff; 41 } 42 43 return 0; 44 } 45 46 static ssize_t wm831x_unique_id_show(struct device *dev, 47 struct device_attribute *attr, char *buf) 48 { 49 struct wm831x *wm831x = dev_get_drvdata(dev); 50 int rval; 51 char id[WM831X_UNIQUE_ID_LEN]; 52 53 rval = wm831x_unique_id_read(wm831x, id); 54 if (rval < 0) 55 return 0; 56 57 return sprintf(buf, "%*phN\n", WM831X_UNIQUE_ID_LEN, id); 58 } 59 60 static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL); 61 62 int wm831x_otp_init(struct wm831x *wm831x) 63 { 64 char uuid[WM831X_UNIQUE_ID_LEN]; 65 int ret; 66 67 ret = device_create_file(wm831x->dev, &dev_attr_unique_id); 68 if (ret != 0) 69 dev_err(wm831x->dev, "Unique ID attribute not created: %d\n", 70 ret); 71 72 ret = wm831x_unique_id_read(wm831x, uuid); 73 if (ret == 0) 74 add_device_randomness(uuid, sizeof(uuid)); 75 else 76 dev_err(wm831x->dev, "Failed to read UUID: %d\n", ret); 77 78 return ret; 79 } 80 81 void wm831x_otp_exit(struct wm831x *wm831x) 82 { 83 device_remove_file(wm831x->dev, &dev_attr_unique_id); 84 } 85 86