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

unicore32 machine related files: add i2c bus drivers for pkunity-v3 soc

change from original version -- by advice of Jean Delvare
1. remove global variable i2c_reg, replaced by local variables
2. replace ENXIO with ENODEV when no platform resources
3. add adapter->nr assignment before i2c_add_numbered_adapter() call
4. add judgement for i2c_del_adapter() return value
5. release adapter when driver removed
6. add __devexit for puv3_i2c_remove() function
7. modify several names to more appropriated ones

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Acked-by: Arnd Bergmann <arnd@arndb.de>

+323
+1
MAINTAINERS
··· 4901 4901 S: Maintained 4902 4902 T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git 4903 4903 F: drivers/input/serio/i8042-unicore32io.h 4904 + F: drivers/i2c/busses/i2c-puv3.c 4904 4905 4905 4906 PMC SIERRA MaxRAID DRIVER 4906 4907 M: Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
+4
arch/unicore32/configs/debug_defconfig
··· 114 114 # Keyboards 115 115 CONFIG_KEYBOARD_GPIO=m 116 116 117 + # I2C support 118 + CONFIG_I2C=y 119 + CONFIG_I2C_PUV3=y 120 + 117 121 # Hardware Monitoring support 118 122 #CONFIG_SENSORS_LM75=m 119 123 # Generic Thermal sysfs driver
+11
drivers/i2c/busses/Kconfig
··· 523 523 This driver can also be built as a module. If so, the module 524 524 will be called i2c-pnx. 525 525 526 + config I2C_PUV3 527 + tristate "PKUnity v3 I2C bus support" 528 + depends on UNICORE32 && ARCH_PUV3 529 + select I2C_ALGOBIT 530 + help 531 + This driver supports the I2C IP inside the PKUnity-v3 SoC. 532 + This I2C bus controller is under AMBA/AXI bus. 533 + 534 + This driver can also be built as a module. If so, the module 535 + will be called i2c-puv3. 536 + 526 537 config I2C_PXA 527 538 tristate "Intel PXA2XX I2C adapter" 528 539 depends on ARCH_PXA || ARCH_MMP
+1
drivers/i2c/busses/Makefile
··· 51 51 obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o 52 52 obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o 53 53 obj-$(CONFIG_I2C_PNX) += i2c-pnx.o 54 + obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o 54 55 obj-$(CONFIG_I2C_PXA) += i2c-pxa.o 55 56 obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o 56 57 obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
+306
drivers/i2c/busses/i2c-puv3.c
··· 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 + */ 30 + static 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 + 51 + static 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 + 85 + static 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 + */ 122 + static 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 + */ 174 + static u32 puv3_i2c_func(struct i2c_adapter *adapter) 175 + { 176 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 177 + } 178 + 179 + static 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 + */ 187 + static 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 + 225 + fail_add_adapter: 226 + platform_set_drvdata(pdev, NULL); 227 + kfree(adapter); 228 + fail_nomem: 229 + release_mem_region(mem->start, resource_size(mem)); 230 + 231 + return rc; 232 + } 233 + 234 + static 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 257 + static 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 + 270 + static 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 + 279 + MODULE_ALIAS("platform:puv3_i2c"); 280 + 281 + static struct platform_driver puv3_i2c_driver = { 282 + .probe = puv3_i2c_probe, 283 + .remove = __devexit_p(puv3_i2c_remove), 284 + .suspend = puv3_i2c_suspend, 285 + .resume = puv3_i2c_resume, 286 + .driver = { 287 + .name = "PKUnity-v3-I2C", 288 + .owner = THIS_MODULE, 289 + } 290 + }; 291 + 292 + static int __init puv3_i2c_init(void) 293 + { 294 + return platform_driver_register(&puv3_i2c_driver); 295 + } 296 + 297 + static void __exit puv3_i2c_exit(void) 298 + { 299 + platform_driver_unregister(&puv3_i2c_driver); 300 + } 301 + 302 + module_init(puv3_i2c_init); 303 + module_exit(puv3_i2c_exit); 304 + 305 + MODULE_DESCRIPTION("PKUnity v3 I2C driver"); 306 + MODULE_LICENSE("GPL v2");