16704e517SMark Brown /* 26704e517SMark Brown * wm831x-otp.c -- OTP for Wolfson WM831x PMICs 36704e517SMark Brown * 46704e517SMark Brown * Copyright 2009 Wolfson Microelectronics PLC. 56704e517SMark Brown * 66704e517SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 76704e517SMark Brown * 86704e517SMark Brown * This program is free software; you can redistribute it and/or modify it 96704e517SMark Brown * under the terms of the GNU General Public License as published by the 106704e517SMark Brown * Free Software Foundation; either version 2 of the License, or (at your 116704e517SMark Brown * option) any later version. 126704e517SMark Brown * 136704e517SMark Brown */ 146704e517SMark Brown 156704e517SMark Brown #include <linux/kernel.h> 166704e517SMark Brown #include <linux/module.h> 176704e517SMark Brown #include <linux/i2c.h> 186704e517SMark Brown #include <linux/bcd.h> 196704e517SMark Brown #include <linux/delay.h> 206704e517SMark Brown #include <linux/mfd/core.h> 216704e517SMark Brown 226704e517SMark Brown #include <linux/mfd/wm831x/core.h> 236704e517SMark Brown #include <linux/mfd/wm831x/otp.h> 246704e517SMark Brown 256704e517SMark Brown /* In bytes */ 266704e517SMark Brown #define WM831X_UNIQUE_ID_LEN 16 276704e517SMark Brown 286704e517SMark Brown /* Read the unique ID from the chip into id */ 296704e517SMark Brown static int wm831x_unique_id_read(struct wm831x *wm831x, char *id) 306704e517SMark Brown { 316704e517SMark Brown int i, val; 326704e517SMark Brown 336704e517SMark Brown for (i = 0; i < WM831X_UNIQUE_ID_LEN / 2; i++) { 346704e517SMark Brown val = wm831x_reg_read(wm831x, WM831X_UNIQUE_ID_1 + i); 356704e517SMark Brown if (val < 0) 366704e517SMark Brown return val; 376704e517SMark Brown 386704e517SMark Brown id[i * 2] = (val >> 8) & 0xff; 396704e517SMark Brown id[(i * 2) + 1] = val & 0xff; 406704e517SMark Brown } 416704e517SMark Brown 426704e517SMark Brown return 0; 436704e517SMark Brown } 446704e517SMark Brown 456704e517SMark Brown static ssize_t wm831x_unique_id_show(struct device *dev, 466704e517SMark Brown struct device_attribute *attr, char *buf) 476704e517SMark Brown { 486704e517SMark Brown struct wm831x *wm831x = dev_get_drvdata(dev); 496704e517SMark Brown int i, rval; 506704e517SMark Brown char id[WM831X_UNIQUE_ID_LEN]; 516704e517SMark Brown ssize_t ret = 0; 526704e517SMark Brown 536704e517SMark Brown rval = wm831x_unique_id_read(wm831x, id); 546704e517SMark Brown if (rval < 0) 556704e517SMark Brown return 0; 566704e517SMark Brown 576704e517SMark Brown for (i = 0; i < WM831X_UNIQUE_ID_LEN; i++) 586704e517SMark Brown ret += sprintf(&buf[ret], "%02x", buf[i]); 596704e517SMark Brown 606704e517SMark Brown ret += sprintf(&buf[ret], "\n"); 616704e517SMark Brown 626704e517SMark Brown return ret; 636704e517SMark Brown } 646704e517SMark Brown 656704e517SMark Brown static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL); 666704e517SMark Brown 676704e517SMark Brown int wm831x_otp_init(struct wm831x *wm831x) 686704e517SMark Brown { 696704e517SMark Brown int ret; 706704e517SMark Brown 716704e517SMark Brown ret = device_create_file(wm831x->dev, &dev_attr_unique_id); 726704e517SMark Brown if (ret != 0) 736704e517SMark Brown dev_err(wm831x->dev, "Unique ID attribute not created: %d\n", 746704e517SMark Brown ret); 756704e517SMark Brown 766704e517SMark Brown return ret; 776704e517SMark Brown } 786704e517SMark Brown 796704e517SMark Brown void wm831x_otp_exit(struct wm831x *wm831x) 806704e517SMark Brown { 816704e517SMark Brown device_remove_file(wm831x->dev, &dev_attr_unique_id); 826704e517SMark Brown } 836704e517SMark Brown 84