1d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao/* 2d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * I2C driver for PKUnity-v3 SoC 3d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Code specific to PKUnity SoC and UniCore ISA 4d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * 5d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> 6d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Copyright (C) 2001-2010 Guan Xuetao 7d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * 8d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * This program is free software; you can redistribute it and/or modify 9d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * it under the terms of the GNU General Public License version 2 as 10d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * published by the Free Software Foundation. 11d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao */ 12d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 13d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/module.h> 14d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/kernel.h> 15d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/err.h> 16d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/slab.h> 17d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/types.h> 18d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/delay.h> 19d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/i2c.h> 20d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/init.h> 21d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/clk.h> 22d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/platform_device.h> 23d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <linux/io.h> 24d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#include <mach/hardware.h> 25d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 26d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao/* 27d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Poll the i2c status register until the specified bit is set. 28d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Returns 0 if timed out (100 msec). 29d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao */ 30d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic short poll_status(unsigned long bit) 31d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 32d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int loop_cntr = 1000; 33d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 34d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (bit & I2C_STATUS_TFNF) { 35d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao do { 36d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao udelay(10); 37d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0)); 38d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } else { 39d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* RXRDY handler */ 40d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao do { 41d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (readl(I2C_TAR) == I2C_TAR_EEPROM) 42d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao msleep(20); 43d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao else 44d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao udelay(10); 45d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0)); 46d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 47d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 48d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return (loop_cntr > 0); 49d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 50d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 51d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) 52d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 53d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int i2c_reg = *buf; 54d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 55d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Read data */ 56d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao while (length--) { 57d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (!poll_status(I2C_STATUS_TFNF)) { 58d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n"); 59d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return -ETIMEDOUT; 60d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 61d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 62d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* send addr */ 63d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); 64d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 65d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* get ready to next write */ 66d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao i2c_reg++; 67d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 68d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* send read CMD */ 69d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(I2C_DATACMD_READ, I2C_DATACMD); 70d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 71d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* wait until the Rx FIFO have available */ 72d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (!poll_status(I2C_STATUS_RFNE)) { 73d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_dbg(&adap->dev, "RXRDY timeout\n"); 74d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return -ETIMEDOUT; 75d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 76d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 77d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* read the data to buf */ 78d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK); 79d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao buf++; 80d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 81d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 82d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0; 83d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 84d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 85d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) 86d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 87d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int i2c_reg = *buf; 88d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 89d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Do nothing but storing the reg_num to a static variable */ 90d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (i2c_reg == -1) { 91d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao printk(KERN_WARNING "Error i2c reg\n"); 92d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return -ETIMEDOUT; 93d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 94d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 95d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (length == 1) 96d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0; 97d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 98d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao buf++; 99d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao length--; 100d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao while (length--) { 101d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* send addr */ 102d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); 103d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 104d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* send write CMD */ 105d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD); 106d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 107d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* wait until the Rx FIFO have available */ 108d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao msleep(20); 109d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 110d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* read the data to buf */ 111d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao i2c_reg++; 112d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao buf++; 113d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 114d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 115d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0; 116d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 117d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 118d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao/* 119d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Generic i2c master transfer entrypoint. 120d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * 121d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao */ 122d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, 123d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int num) 124d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 125d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int i, ret; 126d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao unsigned char swap; 127d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 128d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Disable i2c */ 129d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(I2C_ENABLE_DISABLE, I2C_ENABLE); 130d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 131d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Set the work mode and speed*/ 132d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON); 133d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 134d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(pmsg->addr, I2C_TAR); 135d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 136d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Enable i2c */ 137d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(I2C_ENABLE_ENABLE, I2C_ENABLE); 138d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 139d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num); 140d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 141d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao for (i = 0; i < num; i++) { 142d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, 143d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg->flags & I2C_M_RD ? "read" : "writ", 144d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg->len, pmsg->len > 1 ? "s" : "", 145d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); 146d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 147d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (pmsg->len && pmsg->buf) { /* sanity check */ 148d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (pmsg->flags & I2C_M_RD) 149d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao ret = xfer_read(adap, pmsg->buf, pmsg->len); 150d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao else 151d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao ret = xfer_write(adap, pmsg->buf, pmsg->len); 152d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 153d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (ret) 154d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return ret; 155d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 156d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 157d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_dbg(&adap->dev, "transfer complete\n"); 158d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg++; /* next message */ 159d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 160d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 161d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* XXX: fixup be16_to_cpu in bq27x00_battery.c */ 162d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (pmsg->addr == I2C_TAR_PWIC) { 163d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao swap = pmsg->buf[0]; 164d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg->buf[0] = pmsg->buf[1]; 165d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao pmsg->buf[1] = swap; 166d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 167d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 168d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return i; 169d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 170d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 171d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao/* 172d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Return list of supported functionality. 173d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao */ 174d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic u32 puv3_i2c_func(struct i2c_adapter *adapter) 175d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 176d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 177d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 178d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 179d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic struct i2c_algorithm puv3_i2c_algorithm = { 180d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .master_xfer = puv3_i2c_xfer, 181d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .functionality = puv3_i2c_func, 182d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao}; 183d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 184d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao/* 185d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao * Main initialization routine. 186d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao */ 187d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int __devinit puv3_i2c_probe(struct platform_device *pdev) 188d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 189d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao struct i2c_adapter *adapter; 190d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao struct resource *mem; 191d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int rc; 192d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 193d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 194d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (!mem) 195d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return -ENODEV; 196d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 197d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c")) 198d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return -EBUSY; 199d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 200d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); 201d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (adapter == NULL) { 202d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_err(&pdev->dev, "can't allocate inteface!\n"); 203d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao rc = -ENOMEM; 204d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao goto fail_nomem; 205d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 206d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x", 207d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao mem->start); 208d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->algo = &puv3_i2c_algorithm; 209d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->class = I2C_CLASS_HWMON; 210d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->dev.parent = &pdev->dev; 211d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 212d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao platform_set_drvdata(pdev, adapter); 213d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 214d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->nr = pdev->id; 215d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao rc = i2c_add_numbered_adapter(adapter); 216d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (rc) { 217d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_err(&pdev->dev, "Adapter '%s' registration failed\n", 218d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->name); 219d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao goto fail_add_adapter; 220d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 221d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 222d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); 223d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0; 224d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 225d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaofail_add_adapter: 226d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao platform_set_drvdata(pdev, NULL); 227d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao kfree(adapter); 228d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaofail_nomem: 229d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao release_mem_region(mem->start, resource_size(mem)); 230d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 231d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return rc; 232d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 233d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 234d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int __devexit puv3_i2c_remove(struct platform_device *pdev) 235d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 236d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao struct i2c_adapter *adapter = platform_get_drvdata(pdev); 237d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao struct resource *mem; 238d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int rc; 239d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 240d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao rc = i2c_del_adapter(adapter); 241d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (rc) { 242d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao dev_err(&pdev->dev, "Adapter '%s' delete fail\n", 243d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao adapter->name); 244d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return rc; 245d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 246d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 247d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao put_device(&pdev->dev); 248d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao platform_set_drvdata(pdev, NULL); 249d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 250d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 251d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao release_mem_region(mem->start, resource_size(mem)); 252d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 253d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return rc; 254d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 255d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 256d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#ifdef CONFIG_PM 257d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) 258d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 259d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao int poll_count; 260d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao /* Disable the IIC */ 261d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao writel(I2C_ENABLE_DISABLE, I2C_ENABLE); 262d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao for (poll_count = 0; poll_count < 50; poll_count++) { 263d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE) 264d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao udelay(25); 265d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 266d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 267d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0; 268d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 269d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 270d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic int puv3_i2c_resume(struct platform_device *dev) 271d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao{ 272d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao return 0 ; 273d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao} 274d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#else 275d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#define puv3_i2c_suspend NULL 276d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#define puv3_i2c_resume NULL 277d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao#endif 278d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 279d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaostatic struct platform_driver puv3_i2c_driver = { 280d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .probe = puv3_i2c_probe, 281d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .remove = __devexit_p(puv3_i2c_remove), 282d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .suspend = puv3_i2c_suspend, 283d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .resume = puv3_i2c_resume, 284d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .driver = { 285d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .name = "PKUnity-v3-I2C", 286d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao .owner = THIS_MODULE, 287d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao } 288d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao}; 289d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 290858af58f67d4aba8afb02438e74292b9273cdb10Guan Xuetaomodule_platform_driver(puv3_i2c_driver); 291d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetao 292d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaoMODULE_DESCRIPTION("PKUnity v3 I2C driver"); 293d10e4a660d11212a41ac5d2c116a655e25e2d38aGuanXuetaoMODULE_LICENSE("GPL v2"); 294858af58f67d4aba8afb02438e74292b9273cdb10Guan XuetaoMODULE_ALIAS("platform:puv3_i2c"); 295