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