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