1/* ------------------------------------------------------------------------- */ 2/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x */ 3/* ------------------------------------------------------------------------- */ 4/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd 5 * <Peter dot Milne at D hyphen TACQ dot com> 6 * 7 * With acknowledgements to i2c-algo-ibm_ocp.c by 8 * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com 9 * 10 * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund: 11 * 12 * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund 13 * 14 * And which acknowledged Ky��sti M��lkki <kmalkki@cc.hut.fi>, 15 * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> 16 * 17 * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: 18 * 19 * - Use driver model to pass per-chip info instead of hardcoding and #ifdefs 20 * - Use ioremap/__raw_readl/__raw_writel instead of direct dereference 21 * - Make it work with IXP46x chips 22 * - Cleanup function names, coding style, etc 23 * 24 * - writing to slave address causes latchup on iop331. 25 * fix: driver refuses to address self. 26 * 27 * This program is free software; you can redistribute it and/or modify 28 * it under the terms of the GNU General Public License as published by 29 * the Free Software Foundation, version 2. 30 */ 31 32#include <linux/interrupt.h> 33#include <linux/kernel.h> 34#include <linux/module.h> 35#include <linux/delay.h> 36#include <linux/slab.h> 37#include <linux/init.h> 38#include <linux/errno.h> 39#include <linux/platform_device.h> 40#include <linux/i2c.h> 41 42#include <asm/io.h> 43 44#include "i2c-iop3xx.h" 45 46/* global unit counter */ 47static int i2c_id; 48 49static inline unsigned char 50iic_cook_addr(struct i2c_msg *msg) 51{ 52 unsigned char addr; 53 54 addr = (msg->addr << 1); 55 56 if (msg->flags & I2C_M_RD) 57 addr |= 1; 58 59 /* 60 * Read or Write? 61 */ 62 if (msg->flags & I2C_M_REV_DIR_ADDR) 63 addr ^= 1; 64 65 return addr; 66} 67 68static void 69iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap) 70{ 71 /* Follows devman 9.3 */ 72 __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET); 73 __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET); 74 __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET); 75} 76 77static void 78iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) 79{ 80 u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; 81 82 /* 83 * Every time unit enable is asserted, GPOD needs to be cleared 84 * on IOP3XX to avoid data corruption on the bus. 85 */ 86#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) 87 if (iop3xx_adap->id == 0) { 88 gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW); 89 gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW); 90 } else { 91 gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW); 92 gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW); 93 } 94#endif 95 /* NB SR bits not same position as CR IE bits :-( */ 96 iop3xx_adap->SR_enabled = 97 IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD | 98 IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY; 99 100 cr |= IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE | 101 IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE; 102 103 __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); 104} 105 106static void 107iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) 108{ 109 unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); 110 111 cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | 112 IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN); 113 114 __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); 115} 116 117/* 118 * NB: the handler has to clear the source of the interrupt! 119 * Then it passes the SR flags of interest to BH via adap data 120 */ 121static irqreturn_t 122iop3xx_i2c_irq_handler(int this_irq, void *dev_id) 123{ 124 struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id; 125 u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET); 126 127 if ((sr &= iop3xx_adap->SR_enabled)) { 128 __raw_writel(sr, iop3xx_adap->ioaddr + SR_OFFSET); 129 iop3xx_adap->SR_received |= sr; 130 wake_up_interruptible(&iop3xx_adap->waitq); 131 } 132 return IRQ_HANDLED; 133} 134 135/* check all error conditions, clear them , report most important */ 136static int 137iop3xx_i2c_error(u32 sr) 138{ 139 int rc = 0; 140 141 if ((sr & IOP3XX_ISR_BERRD)) { 142 if ( !rc ) rc = -I2C_ERR_BERR; 143 } 144 if ((sr & IOP3XX_ISR_ALD)) { 145 if ( !rc ) rc = -I2C_ERR_ALD; 146 } 147 return rc; 148} 149 150static inline u32 151iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap) 152{ 153 unsigned long flags; 154 u32 sr; 155 156 spin_lock_irqsave(&iop3xx_adap->lock, flags); 157 sr = iop3xx_adap->SR_received; 158 iop3xx_adap->SR_received = 0; 159 spin_unlock_irqrestore(&iop3xx_adap->lock, flags); 160 161 return sr; 162} 163 164/* 165 * sleep until interrupted, then recover and analyse the SR 166 * saved by handler 167 */ 168typedef int (* compare_func)(unsigned test, unsigned mask); 169/* returns 1 on correct comparison */ 170 171static int 172iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, 173 unsigned flags, unsigned* status, 174 compare_func compare) 175{ 176 unsigned sr = 0; 177 int interrupted; 178 int done; 179 int rc = 0; 180 181 do { 182 interrupted = wait_event_interruptible_timeout ( 183 iop3xx_adap->waitq, 184 (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), 185 1 * HZ; 186 ); 187 if ((rc = iop3xx_i2c_error(sr)) < 0) { 188 *status = sr; 189 return rc; 190 } else if (!interrupted) { 191 *status = sr; 192 return -ETIMEDOUT; 193 } 194 } while(!done); 195 196 *status = sr; 197 198 return 0; 199} 200 201/* 202 * Concrete compare_funcs 203 */ 204static int 205all_bits_clear(unsigned test, unsigned mask) 206{ 207 return (test & mask) == 0; 208} 209 210static int 211any_bits_set(unsigned test, unsigned mask) 212{ 213 return (test & mask) != 0; 214} 215 216static int 217iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) 218{ 219 return iop3xx_i2c_wait_event( 220 iop3xx_adap, 221 IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, 222 status, any_bits_set); 223} 224 225static int 226iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) 227{ 228 return iop3xx_i2c_wait_event( 229 iop3xx_adap, 230 IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, 231 status, any_bits_set); 232} 233 234static int 235iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) 236{ 237 return iop3xx_i2c_wait_event( 238 iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear); 239} 240 241static int 242iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, 243 struct i2c_msg* msg) 244{ 245 unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); 246 int status; 247 int rc; 248 249 /* avoid writing to my slave address (hangs on 80331), 250 * forbidden in Intel developer manual 251 */ 252 if (msg->addr == MYSAR) { 253 return -EBUSY; 254 } 255 256 __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET); 257 258 cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK); 259 cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE; 260 261 __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); 262 rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status); 263 264 return rc; 265} 266 267static int 268iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, 269 int stop) 270{ 271 unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); 272 int status; 273 int rc = 0; 274 275 __raw_writel(byte, iop3xx_adap->ioaddr + DBR_OFFSET); 276 cr &= ~IOP3XX_ICR_MSTART; 277 if (stop) { 278 cr |= IOP3XX_ICR_MSTOP; 279 } else { 280 cr &= ~IOP3XX_ICR_MSTOP; 281 } 282 cr |= IOP3XX_ICR_TBYTE; 283 __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); 284 rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status); 285 286 return rc; 287} 288 289static int 290iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, 291 int stop) 292{ 293 unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); 294 int status; 295 int rc = 0; 296 297 cr &= ~IOP3XX_ICR_MSTART; 298 299 if (stop) { 300 cr |= IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK; 301 } else { 302 cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK); 303 } 304 cr |= IOP3XX_ICR_TBYTE; 305 __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); 306 307 rc = iop3xx_i2c_wait_rx_done(iop3xx_adap, &status); 308 309 *byte = __raw_readl(iop3xx_adap->ioaddr + DBR_OFFSET); 310 311 return rc; 312} 313 314static int 315iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count) 316{ 317 struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; 318 int ii; 319 int rc = 0; 320 321 for (ii = 0; rc == 0 && ii != count; ++ii) 322 rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1); 323 return rc; 324} 325 326static int 327iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) 328{ 329 struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; 330 int ii; 331 int rc = 0; 332 333 for (ii = 0; rc == 0 && ii != count; ++ii) 334 rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1); 335 336 return rc; 337} 338 339/* 340 * Description: This function implements combined transactions. Combined 341 * transactions consist of combinations of reading and writing blocks of data. 342 * FROM THE SAME ADDRESS 343 * Each transfer (i.e. a read or a write) is separated by a repeated start 344 * condition. 345 */ 346static int 347iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) 348{ 349 struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; 350 int rc; 351 352 rc = iop3xx_i2c_send_target_addr(iop3xx_adap, pmsg); 353 if (rc < 0) { 354 return rc; 355 } 356 357 if ((pmsg->flags&I2C_M_RD)) { 358 return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len); 359 } else { 360 return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len); 361 } 362} 363 364/* 365 * master_xfer() - main read/write entry 366 */ 367static int 368iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 369 int num) 370{ 371 struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; 372 int im = 0; 373 int ret = 0; 374 int status; 375 376 iop3xx_i2c_wait_idle(iop3xx_adap, &status); 377 iop3xx_i2c_reset(iop3xx_adap); 378 iop3xx_i2c_enable(iop3xx_adap); 379 380 for (im = 0; ret == 0 && im != num; im++) { 381 ret = iop3xx_i2c_handle_msg(i2c_adap, &msgs[im]); 382 } 383 384 iop3xx_i2c_transaction_cleanup(iop3xx_adap); 385 386 if(ret) 387 return ret; 388 389 return im; 390} 391 392static int 393iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd, 394 unsigned long arg) 395{ 396 return 0; 397} 398 399static u32 400iop3xx_i2c_func(struct i2c_adapter *adap) 401{ 402 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 403} 404 405static const struct i2c_algorithm iop3xx_i2c_algo = { 406 .master_xfer = iop3xx_i2c_master_xfer, 407 .algo_control = iop3xx_i2c_algo_control, 408 .functionality = iop3xx_i2c_func, 409}; 410 411static int 412iop3xx_i2c_remove(struct platform_device *pdev) 413{ 414 struct i2c_adapter *padapter = platform_get_drvdata(pdev); 415 struct i2c_algo_iop3xx_data *adapter_data = 416 (struct i2c_algo_iop3xx_data *)padapter->algo_data; 417 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 418 unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET); 419 420 /* 421 * Disable the actual HW unit 422 */ 423 cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE | 424 IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE); 425 __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET); 426 427 iounmap((void __iomem*)adapter_data->ioaddr); 428 release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); 429 kfree(adapter_data); 430 kfree(padapter); 431 432 platform_set_drvdata(pdev, NULL); 433 434 return 0; 435} 436 437static int 438iop3xx_i2c_probe(struct platform_device *pdev) 439{ 440 struct resource *res; 441 int ret, irq; 442 struct i2c_adapter *new_adapter; 443 struct i2c_algo_iop3xx_data *adapter_data; 444 445 new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); 446 if (!new_adapter) { 447 ret = -ENOMEM; 448 goto out; 449 } 450 451 adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); 452 if (!adapter_data) { 453 ret = -ENOMEM; 454 goto free_adapter; 455 } 456 457 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 458 if (!res) { 459 ret = -ENODEV; 460 goto free_both; 461 } 462 463 if (!request_mem_region(res->start, IOP3XX_I2C_IO_SIZE, pdev->name)) { 464 ret = -EBUSY; 465 goto free_both; 466 } 467 468 /* set the adapter enumeration # */ 469 adapter_data->id = i2c_id++; 470 471 adapter_data->ioaddr = (u32)ioremap(res->start, IOP3XX_I2C_IO_SIZE); 472 if (!adapter_data->ioaddr) { 473 ret = -ENOMEM; 474 goto release_region; 475 } 476 477 irq = platform_get_irq(pdev, 0); 478 if (irq < 0) { 479 ret = -ENXIO; 480 goto unmap; 481 } 482 ret = request_irq(irq, iop3xx_i2c_irq_handler, 0, 483 pdev->name, adapter_data); 484 485 if (ret) { 486 ret = -EIO; 487 goto unmap; 488 } 489 490 memcpy(new_adapter->name, pdev->name, strlen(pdev->name)); 491 new_adapter->id = I2C_HW_IOP3XX; 492 new_adapter->owner = THIS_MODULE; 493 new_adapter->dev.parent = &pdev->dev; 494 495 /* 496 * Default values...should these come in from board code? 497 */ 498 new_adapter->timeout = 100; 499 new_adapter->retries = 3; 500 new_adapter->algo = &iop3xx_i2c_algo; 501 502 init_waitqueue_head(&adapter_data->waitq); 503 spin_lock_init(&adapter_data->lock); 504 505 iop3xx_i2c_reset(adapter_data); 506 iop3xx_i2c_enable(adapter_data); 507 508 platform_set_drvdata(pdev, new_adapter); 509 new_adapter->algo_data = adapter_data; 510 511 i2c_add_adapter(new_adapter); 512 513 return 0; 514 515unmap: 516 iounmap((void __iomem*)adapter_data->ioaddr); 517 518release_region: 519 release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); 520 521free_both: 522 kfree(adapter_data); 523 524free_adapter: 525 kfree(new_adapter); 526 527out: 528 return ret; 529} 530 531 532static struct platform_driver iop3xx_i2c_driver = { 533 .probe = iop3xx_i2c_probe, 534 .remove = iop3xx_i2c_remove, 535 .driver = { 536 .owner = THIS_MODULE, 537 .name = "IOP3xx-I2C", 538 }, 539}; 540 541static int __init 542i2c_iop3xx_init (void) 543{ 544 return platform_driver_register(&iop3xx_i2c_driver); 545} 546 547static void __exit 548i2c_iop3xx_exit (void) 549{ 550 platform_driver_unregister(&iop3xx_i2c_driver); 551 return; 552} 553 554module_init (i2c_iop3xx_init); 555module_exit (i2c_iop3xx_exit); 556 557MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>"); 558MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); 559MODULE_LICENSE("GPL"); 560