1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License 4 * as published by the Free Software Foundation; either version 2 5 * of the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 */ 16 17#include <linux/delay.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/spinlock.h> 21#include <linux/platform_device.h> 22#include <linux/init.h> 23#include <linux/errno.h> 24#include <linux/i2c.h> 25#include <linux/slab.h> 26 27#define PIC32_I2CxCON 0x0000 28#define PIC32_I2CxCONCLR 0x0004 29#define PIC32_I2CxCONSET 0x0008 30#define PIC32_I2CxCONINV 0x000C 31#define I2CCON_ON (1<<15) 32#define I2CCON_FRZ (1<<14) 33#define I2CCON_SIDL (1<<13) 34#define I2CCON_SCLREL (1<<12) 35#define I2CCON_STRICT (1<<11) 36#define I2CCON_A10M (1<<10) 37#define I2CCON_DISSLW (1<<9) 38#define I2CCON_SMEN (1<<8) 39#define I2CCON_GCEN (1<<7) 40#define I2CCON_STREN (1<<6) 41#define I2CCON_ACKDT (1<<5) 42#define I2CCON_ACKEN (1<<4) 43#define I2CCON_RCEN (1<<3) 44#define I2CCON_PEN (1<<2) 45#define I2CCON_RSEN (1<<1) 46#define I2CCON_SEN (1<<0) 47 48#define PIC32_I2CxSTAT 0x0010 49#define PIC32_I2CxSTATCLR 0x0014 50#define PIC32_I2CxSTATSET 0x0018 51#define PIC32_I2CxSTATINV 0x001C 52#define I2CSTAT_ACKSTAT (1<<15) 53#define I2CSTAT_TRSTAT (1<<14) 54#define I2CSTAT_BCL (1<<10) 55#define I2CSTAT_GCSTAT (1<<9) 56#define I2CSTAT_ADD10 (1<<8) 57#define I2CSTAT_IWCOL (1<<7) 58#define I2CSTAT_I2COV (1<<6) 59#define I2CSTAT_DA (1<<5) 60#define I2CSTAT_P (1<<4) 61#define I2CSTAT_S (1<<3) 62#define I2CSTAT_RW (1<<2) 63#define I2CSTAT_RBF (1<<1) 64#define I2CSTAT_TBF (1<<0) 65 66#define PIC32_I2CxADD 0x0020 67#define PIC32_I2CxADDCLR 0x0024 68#define PIC32_I2CxADDSET 0x0028 69#define PIC32_I2CxADDINV 0x002C 70#define PIC32_I2CxMSK 0x0030 71#define PIC32_I2CxMSKCLR 0x0034 72#define PIC32_I2CxMSKSET 0x0038 73#define PIC32_I2CxMSKINV 0x003C 74#define PIC32_I2CxBRG 0x0040 75#define PIC32_I2CxBRGCLR 0x0044 76#define PIC32_I2CxBRGSET 0x0048 77#define PIC32_I2CxBRGINV 0x004C 78#define PIC32_I2CxTRN 0x0050 79#define PIC32_I2CxTRNCLR 0x0054 80#define PIC32_I2CxTRNSET 0x0058 81#define PIC32_I2CxTRNINV 0x005C 82#define PIC32_I2CxRCV 0x0060 83 84struct i2c_platform_data { 85 u32 base; 86 struct i2c_adapter adap; 87 u32 xfer_timeout; 88 u32 ack_timeout; 89 u32 ctl_timeout; 90}; 91 92extern u32 pic32_bus_readl(u32 reg); 93extern void pic32_bus_writel(u32 val, u32 reg); 94 95static inline void 96StartI2C(struct i2c_platform_data *adap) 97{ 98 pr_debug("StartI2C\n"); 99 pic32_bus_writel(I2CCON_SEN, adap->base + PIC32_I2CxCONSET); 100} 101 102static inline void 103StopI2C(struct i2c_platform_data *adap) 104{ 105 pr_debug("StopI2C\n"); 106 pic32_bus_writel(I2CCON_PEN, adap->base + PIC32_I2CxCONSET); 107} 108 109static inline void 110AckI2C(struct i2c_platform_data *adap) 111{ 112 pr_debug("AckI2C\n"); 113 pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONCLR); 114 pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); 115} 116 117static inline void 118NotAckI2C(struct i2c_platform_data *adap) 119{ 120 pr_debug("NakI2C\n"); 121 pic32_bus_writel(I2CCON_ACKDT, adap->base + PIC32_I2CxCONSET); 122 pic32_bus_writel(I2CCON_ACKEN, adap->base + PIC32_I2CxCONSET); 123} 124 125static inline int 126IdleI2C(struct i2c_platform_data *adap) 127{ 128 int i; 129 130 pr_debug("IdleI2C\n"); 131 for (i = 0; i < adap->ctl_timeout; i++) { 132 if (((pic32_bus_readl(adap->base + PIC32_I2CxCON) & 133 (I2CCON_ACKEN|I2CCON_RCEN|I2CCON_PEN|I2CCON_RSEN|I2CCON_SEN)) == 0) && 134 ((pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & 135 (I2CSTAT_TRSTAT)) == 0)) 136 return 0; 137 udelay(1); 138 } 139 return -ETIMEDOUT; 140} 141 142static inline u32 143MasterWriteI2C(struct i2c_platform_data *adap, u32 byte) 144{ 145 pr_debug("MasterWriteI2C\n"); 146 147 pic32_bus_writel(byte, adap->base + PIC32_I2CxTRN); 148 149 return pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_IWCOL; 150} 151 152static inline u32 153MasterReadI2C(struct i2c_platform_data *adap) 154{ 155 pr_debug("MasterReadI2C\n"); 156 157 pic32_bus_writel(I2CCON_RCEN, adap->base + PIC32_I2CxCONSET); 158 159 while (pic32_bus_readl(adap->base + PIC32_I2CxCON) & I2CCON_RCEN) 160 ; 161 162 pic32_bus_writel(I2CSTAT_I2COV, adap->base + PIC32_I2CxSTATCLR); 163 164 return pic32_bus_readl(adap->base + PIC32_I2CxRCV); 165} 166 167static int 168do_address(struct i2c_platform_data *adap, unsigned int addr, int rd) 169{ 170 pr_debug("doaddress\n"); 171 172 IdleI2C(adap); 173 StartI2C(adap); 174 IdleI2C(adap); 175 176 addr <<= 1; 177 if (rd) 178 addr |= 1; 179 180 if (MasterWriteI2C(adap, addr)) 181 return -EIO; 182 IdleI2C(adap); 183 if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_ACKSTAT) 184 return -EIO; 185 return 0; 186} 187 188static int 189i2c_read(struct i2c_platform_data *adap, unsigned char *buf, 190 unsigned int len) 191{ 192 int i; 193 u32 data; 194 195 pr_debug("i2c_read\n"); 196 197 i = 0; 198 while (i < len) { 199 data = MasterReadI2C(adap); 200 buf[i++] = data; 201 if (i < len) 202 AckI2C(adap); 203 else 204 NotAckI2C(adap); 205 } 206 207 StopI2C(adap); 208 IdleI2C(adap); 209 return 0; 210} 211 212static int 213i2c_write(struct i2c_platform_data *adap, unsigned char *buf, 214 unsigned int len) 215{ 216 int i; 217 u32 data; 218 219 pr_debug("i2c_write\n"); 220 221 i = 0; 222 while (i < len) { 223 data = buf[i]; 224 if (MasterWriteI2C(adap, data)) 225 return -EIO; 226 IdleI2C(adap); 227 if (pic32_bus_readl(adap->base + PIC32_I2CxSTAT) & I2CSTAT_ACKSTAT) 228 return -EIO; 229 i++; 230 } 231 232 StopI2C(adap); 233 IdleI2C(adap); 234 return 0; 235} 236 237static int 238platform_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) 239{ 240 struct i2c_platform_data *adap = i2c_adap->algo_data; 241 struct i2c_msg *p; 242 int i, err = 0; 243 244 pr_debug("platform_xfer\n"); 245 for (i = 0; i < num; i++) { 246#define __BUFSIZE 80 247 int ii; 248 static char buf[__BUFSIZE]; 249 char *b = buf; 250 251 p = &msgs[i]; 252 b += sprintf(buf, " [%d bytes]", p->len); 253 if ((p->flags & I2C_M_RD) == 0) { 254 for (ii = 0; ii < p->len; ii++) { 255 if (b < &buf[__BUFSIZE-4]) { 256 b += sprintf(b, " %02x", p->buf[ii]); 257 } else { 258 strcat(b, "..."); 259 break; 260 } 261 } 262 } 263 pr_debug("xfer%d: DevAddr: %04x Op:%s Data:%s\n", i, p->addr, 264 (p->flags & I2C_M_RD) ? "Rd" : "Wr", buf); 265 } 266 267 268 for (i = 0; !err && i < num; i++) { 269 p = &msgs[i]; 270 err = do_address(adap, p->addr, p->flags & I2C_M_RD); 271 if (err || !p->len) 272 continue; 273 if (p->flags & I2C_M_RD) 274 err = i2c_read(adap, p->buf, p->len); 275 else 276 err = i2c_write(adap, p->buf, p->len); 277 } 278 279 /* Return the number of messages processed, or the error code. */ 280 if (err == 0) 281 err = num; 282 283 return err; 284} 285 286static u32 287platform_func(struct i2c_adapter *adap) 288{ 289 pr_debug("platform_algo\n"); 290 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 291} 292 293static const struct i2c_algorithm platform_algo = { 294 .master_xfer = platform_xfer, 295 .functionality = platform_func, 296}; 297 298static void i2c_platform_setup(struct i2c_platform_data *priv) 299{ 300 pr_debug("i2c_platform_setup\n"); 301 302 pic32_bus_writel(500, priv->base + PIC32_I2CxBRG); 303 pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONCLR); 304 pic32_bus_writel(I2CCON_ON, priv->base + PIC32_I2CxCONSET); 305 pic32_bus_writel(I2CSTAT_BCL|I2CSTAT_IWCOL, priv->base + PIC32_I2CxSTATCLR); 306} 307 308static void i2c_platform_disable(struct i2c_platform_data *priv) 309{ 310 pr_debug("i2c_platform_disable\n"); 311} 312 313static int __devinit 314i2c_platform_probe(struct platform_device *pdev) 315{ 316 struct i2c_platform_data *priv; 317 struct resource *r; 318 int ret; 319 320 pr_debug("i2c_platform_probe\n"); 321 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 322 if (!r) { 323 ret = -ENODEV; 324 goto out; 325 } 326 327 priv = kzalloc(sizeof(struct i2c_platform_data), GFP_KERNEL); 328 if (!priv) { 329 ret = -ENOMEM; 330 goto out; 331 } 332 333 priv->base = r->start; 334 if (!priv->base) { 335 ret = -EBUSY; 336 goto out_mem; 337 } 338 339 priv->xfer_timeout = 200; 340 priv->ack_timeout = 200; 341 priv->ctl_timeout = 200; 342 343 priv->adap.nr = pdev->id; 344 priv->adap.algo = &platform_algo; 345 priv->adap.algo_data = priv; 346 priv->adap.dev.parent = &pdev->dev; 347 strlcpy(priv->adap.name, "PIC32 I2C", sizeof(priv->adap.name)); 348 349 i2c_platform_setup(priv); 350 351 ret = i2c_add_numbered_adapter(&priv->adap); 352 if (ret == 0) { 353 platform_set_drvdata(pdev, priv); 354 return 0; 355 } 356 357 i2c_platform_disable(priv); 358 359out_mem: 360 kfree(priv); 361out: 362 return ret; 363} 364 365static int __devexit 366i2c_platform_remove(struct platform_device *pdev) 367{ 368 struct i2c_platform_data *priv = platform_get_drvdata(pdev); 369 370 pr_debug("i2c_platform_remove\n"); 371 platform_set_drvdata(pdev, NULL); 372 i2c_del_adapter(&priv->adap); 373 i2c_platform_disable(priv); 374 kfree(priv); 375 return 0; 376} 377 378#ifdef CONFIG_PM 379static int 380i2c_platform_suspend(struct platform_device *pdev, pm_message_t state) 381{ 382 struct i2c_platform_data *priv = platform_get_drvdata(pdev); 383 384 dev_dbg(&pdev->dev, "i2c_platform_disable\n"); 385 i2c_platform_disable(priv); 386 387 return 0; 388} 389 390static int 391i2c_platform_resume(struct platform_device *pdev) 392{ 393 struct i2c_platform_data *priv = platform_get_drvdata(pdev); 394 395 dev_dbg(&pdev->dev, "i2c_platform_setup\n"); 396 i2c_platform_setup(priv); 397 398 return 0; 399} 400#else 401#define i2c_platform_suspend NULL 402#define i2c_platform_resume NULL 403#endif 404 405static struct platform_driver i2c_platform_driver = { 406 .driver = { 407 .name = "i2c_pic32", 408 .owner = THIS_MODULE, 409 }, 410 .probe = i2c_platform_probe, 411 .remove = __devexit_p(i2c_platform_remove), 412 .suspend = i2c_platform_suspend, 413 .resume = i2c_platform_resume, 414}; 415 416static int __init 417i2c_platform_init(void) 418{ 419 pr_debug("i2c_platform_init\n"); 420 return platform_driver_register(&i2c_platform_driver); 421} 422 423static void __exit 424i2c_platform_exit(void) 425{ 426 pr_debug("i2c_platform_exit\n"); 427 platform_driver_unregister(&i2c_platform_driver); 428} 429 430MODULE_AUTHOR("Chris Dearman, MIPS Technologies INC."); 431MODULE_DESCRIPTION("PIC32 I2C driver"); 432MODULE_LICENSE("GPL"); 433 434module_init(i2c_platform_init); 435module_exit(i2c_platform_exit); 436