Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.3-rc7 294 lines 6.5 kB view raw
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 __devinit 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 inteface!\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 platform_set_drvdata(pdev, NULL); 227 kfree(adapter); 228fail_nomem: 229 release_mem_region(mem->start, resource_size(mem)); 230 231 return rc; 232} 233 234static int __devexit puv3_i2c_remove(struct platform_device *pdev) 235{ 236 struct i2c_adapter *adapter = platform_get_drvdata(pdev); 237 struct resource *mem; 238 int rc; 239 240 rc = i2c_del_adapter(adapter); 241 if (rc) { 242 dev_err(&pdev->dev, "Adapter '%s' delete fail\n", 243 adapter->name); 244 return rc; 245 } 246 247 put_device(&pdev->dev); 248 platform_set_drvdata(pdev, NULL); 249 250 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 251 release_mem_region(mem->start, resource_size(mem)); 252 253 return rc; 254} 255 256#ifdef CONFIG_PM 257static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) 258{ 259 int poll_count; 260 /* Disable the IIC */ 261 writel(I2C_ENABLE_DISABLE, I2C_ENABLE); 262 for (poll_count = 0; poll_count < 50; poll_count++) { 263 if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE) 264 udelay(25); 265 } 266 267 return 0; 268} 269 270static int puv3_i2c_resume(struct platform_device *dev) 271{ 272 return 0 ; 273} 274#else 275#define puv3_i2c_suspend NULL 276#define puv3_i2c_resume NULL 277#endif 278 279static struct platform_driver puv3_i2c_driver = { 280 .probe = puv3_i2c_probe, 281 .remove = __devexit_p(puv3_i2c_remove), 282 .suspend = puv3_i2c_suspend, 283 .resume = puv3_i2c_resume, 284 .driver = { 285 .name = "PKUnity-v3-I2C", 286 .owner = THIS_MODULE, 287 } 288}; 289 290module_platform_driver(puv3_i2c_driver); 291 292MODULE_DESCRIPTION("PKUnity v3 I2C driver"); 293MODULE_LICENSE("GPL v2"); 294MODULE_ALIAS("platform:puv3_i2c");