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 i, rval; 51 char id[WM831X_UNIQUE_ID_LEN]; 52 ssize_t ret = 0; 53 54 rval = wm831x_unique_id_read(wm831x, id); 55 if (rval < 0) 56 return 0; 57 58 for (i = 0; i < WM831X_UNIQUE_ID_LEN; i++) 59 ret += sprintf(&buf[ret], "%02x", buf[i]); 60 61 ret += sprintf(&buf[ret], "\n"); 62 63 return ret; 64 } 65 66 static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL); 67 68 int wm831x_otp_init(struct wm831x *wm831x) 69 { 70 char uuid[WM831X_UNIQUE_ID_LEN]; 71 int ret; 72 73 ret = device_create_file(wm831x->dev, &dev_attr_unique_id); 74 if (ret != 0) 75 dev_err(wm831x->dev, "Unique ID attribute not created: %d\n", 76 ret); 77 78 ret = wm831x_unique_id_read(wm831x, uuid); 79 if (ret == 0) 80 add_device_randomness(uuid, sizeof(uuid)); 81 else 82 dev_err(wm831x->dev, "Failed to read UUID: %d\n", ret); 83 84 return ret; 85 } 86 87 void wm831x_otp_exit(struct wm831x *wm831x) 88 { 89 device_remove_file(wm831x->dev, &dev_attr_unique_id); 90 } 91 92