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