diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c | 531 |
1 files changed, 0 insertions, 531 deletions
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c b/ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c deleted file mode 100644 index 93f147a9..00000000 --- a/ANDROID_3.4.5/drivers/i2c/busses/i2c-iop3xx.c +++ /dev/null @@ -1,531 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd - * <Peter dot Milne at D hyphen TACQ dot com> - * - * With acknowledgements to i2c-algo-ibm_ocp.c by - * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com - * - * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund: - * - * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund - * - * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, - * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> - * - * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: - * - * - Use driver model to pass per-chip info instead of hardcoding and #ifdefs - * - Use ioremap/__raw_readl/__raw_writel instead of direct dereference - * - Make it work with IXP46x chips - * - Cleanup function names, coding style, etc - * - * - writing to slave address causes latchup on iop331. - * fix: driver refuses to address self. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - */ - -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/platform_device.h> -#include <linux/i2c.h> -#include <linux/io.h> - -#include "i2c-iop3xx.h" - -/* global unit counter */ -static int i2c_id; - -static inline unsigned char -iic_cook_addr(struct i2c_msg *msg) -{ - unsigned char addr; - - addr = (msg->addr << 1); - - if (msg->flags & I2C_M_RD) - addr |= 1; - - return addr; -} - -static void -iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap) -{ - /* Follows devman 9.3 */ - __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET); - __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET); - __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET); -} - -static void -iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) -{ - u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE; - - /* - * Every time unit enable is asserted, GPOD needs to be cleared - * on IOP3XX to avoid data corruption on the bus. - */ -#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) - if (iop3xx_adap->id == 0) { - gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW); - gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW); - } else { - gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW); - gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW); - } -#endif - /* NB SR bits not same position as CR IE bits :-( */ - iop3xx_adap->SR_enabled = - IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD | - IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY; - - cr |= IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE | - IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE; - - __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); -} - -static void -iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap) -{ - unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); - - cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | - IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN); - - __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); -} - -/* - * NB: the handler has to clear the source of the interrupt! - * Then it passes the SR flags of interest to BH via adap data - */ -static irqreturn_t -iop3xx_i2c_irq_handler(int this_irq, void *dev_id) -{ - struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id; - u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET); - - if ((sr &= iop3xx_adap->SR_enabled)) { - __raw_writel(sr, iop3xx_adap->ioaddr + SR_OFFSET); - iop3xx_adap->SR_received |= sr; - wake_up_interruptible(&iop3xx_adap->waitq); - } - return IRQ_HANDLED; -} - -/* check all error conditions, clear them , report most important */ -static int -iop3xx_i2c_error(u32 sr) -{ - int rc = 0; - - if ((sr & IOP3XX_ISR_BERRD)) { - if ( !rc ) rc = -I2C_ERR_BERR; - } - if ((sr & IOP3XX_ISR_ALD)) { - if ( !rc ) rc = -I2C_ERR_ALD; - } - return rc; -} - -static inline u32 -iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap) -{ - unsigned long flags; - u32 sr; - - spin_lock_irqsave(&iop3xx_adap->lock, flags); - sr = iop3xx_adap->SR_received; - iop3xx_adap->SR_received = 0; - spin_unlock_irqrestore(&iop3xx_adap->lock, flags); - - return sr; -} - -/* - * sleep until interrupted, then recover and analyse the SR - * saved by handler - */ -typedef int (* compare_func)(unsigned test, unsigned mask); -/* returns 1 on correct comparison */ - -static int -iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, - unsigned flags, unsigned* status, - compare_func compare) -{ - unsigned sr = 0; - int interrupted; - int done; - int rc = 0; - - do { - interrupted = wait_event_interruptible_timeout ( - iop3xx_adap->waitq, - (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), - 1 * HZ; - ); - if ((rc = iop3xx_i2c_error(sr)) < 0) { - *status = sr; - return rc; - } else if (!interrupted) { - *status = sr; - return -ETIMEDOUT; - } - } while(!done); - - *status = sr; - - return 0; -} - -/* - * Concrete compare_funcs - */ -static int -all_bits_clear(unsigned test, unsigned mask) -{ - return (test & mask) == 0; -} - -static int -any_bits_set(unsigned test, unsigned mask) -{ - return (test & mask) != 0; -} - -static int -iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) -{ - return iop3xx_i2c_wait_event( - iop3xx_adap, - IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, - status, any_bits_set); -} - -static int -iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) -{ - return iop3xx_i2c_wait_event( - iop3xx_adap, - IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD, - status, any_bits_set); -} - -static int -iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status) -{ - return iop3xx_i2c_wait_event( - iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear); -} - -static int -iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, - struct i2c_msg* msg) -{ - unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); - int status; - int rc; - - /* avoid writing to my slave address (hangs on 80331), - * forbidden in Intel developer manual - */ - if (msg->addr == MYSAR) { - return -EBUSY; - } - - __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET); - - cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK); - cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE; - - __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); - rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status); - - return rc; -} - -static int -iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, - int stop) -{ - unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); - int status; - int rc = 0; - - __raw_writel(byte, iop3xx_adap->ioaddr + DBR_OFFSET); - cr &= ~IOP3XX_ICR_MSTART; - if (stop) { - cr |= IOP3XX_ICR_MSTOP; - } else { - cr &= ~IOP3XX_ICR_MSTOP; - } - cr |= IOP3XX_ICR_TBYTE; - __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); - rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status); - - return rc; -} - -static int -iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, - int stop) -{ - unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET); - int status; - int rc = 0; - - cr &= ~IOP3XX_ICR_MSTART; - - if (stop) { - cr |= IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK; - } else { - cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK); - } - cr |= IOP3XX_ICR_TBYTE; - __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET); - - rc = iop3xx_i2c_wait_rx_done(iop3xx_adap, &status); - - *byte = __raw_readl(iop3xx_adap->ioaddr + DBR_OFFSET); - - return rc; -} - -static int -iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count) -{ - struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; - int ii; - int rc = 0; - - for (ii = 0; rc == 0 && ii != count; ++ii) - rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1); - return rc; -} - -static int -iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) -{ - struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; - int ii; - int rc = 0; - - for (ii = 0; rc == 0 && ii != count; ++ii) - rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1); - - return rc; -} - -/* - * Description: This function implements combined transactions. Combined - * transactions consist of combinations of reading and writing blocks of data. - * FROM THE SAME ADDRESS - * Each transfer (i.e. a read or a write) is separated by a repeated start - * condition. - */ -static int -iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) -{ - struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; - int rc; - - rc = iop3xx_i2c_send_target_addr(iop3xx_adap, pmsg); - if (rc < 0) { - return rc; - } - - if ((pmsg->flags&I2C_M_RD)) { - return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len); - } else { - return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len); - } -} - -/* - * master_xfer() - main read/write entry - */ -static int -iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, - int num) -{ - struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; - int im = 0; - int ret = 0; - int status; - - iop3xx_i2c_wait_idle(iop3xx_adap, &status); - iop3xx_i2c_reset(iop3xx_adap); - iop3xx_i2c_enable(iop3xx_adap); - - for (im = 0; ret == 0 && im != num; im++) { - ret = iop3xx_i2c_handle_msg(i2c_adap, &msgs[im]); - } - - iop3xx_i2c_transaction_cleanup(iop3xx_adap); - - if(ret) - return ret; - - return im; -} - -static u32 -iop3xx_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm iop3xx_i2c_algo = { - .master_xfer = iop3xx_i2c_master_xfer, - .functionality = iop3xx_i2c_func, -}; - -static int -iop3xx_i2c_remove(struct platform_device *pdev) -{ - struct i2c_adapter *padapter = platform_get_drvdata(pdev); - struct i2c_algo_iop3xx_data *adapter_data = - (struct i2c_algo_iop3xx_data *)padapter->algo_data; - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET); - - /* - * Disable the actual HW unit - */ - cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE | - IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE); - __raw_writel(cr, adapter_data->ioaddr + CR_OFFSET); - - iounmap(adapter_data->ioaddr); - release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); - kfree(adapter_data); - kfree(padapter); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static int -iop3xx_i2c_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret, irq; - struct i2c_adapter *new_adapter; - struct i2c_algo_iop3xx_data *adapter_data; - - new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); - if (!new_adapter) { - ret = -ENOMEM; - goto out; - } - - adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL); - if (!adapter_data) { - ret = -ENOMEM; - goto free_adapter; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - goto free_both; - } - - if (!request_mem_region(res->start, IOP3XX_I2C_IO_SIZE, pdev->name)) { - ret = -EBUSY; - goto free_both; - } - - /* set the adapter enumeration # */ - adapter_data->id = i2c_id++; - - adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE); - if (!adapter_data->ioaddr) { - ret = -ENOMEM; - goto release_region; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = -ENXIO; - goto unmap; - } - ret = request_irq(irq, iop3xx_i2c_irq_handler, 0, - pdev->name, adapter_data); - - if (ret) { - ret = -EIO; - goto unmap; - } - - memcpy(new_adapter->name, pdev->name, strlen(pdev->name)); - new_adapter->owner = THIS_MODULE; - new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - new_adapter->dev.parent = &pdev->dev; - new_adapter->nr = pdev->id; - - /* - * Default values...should these come in from board code? - */ - new_adapter->timeout = HZ; - new_adapter->algo = &iop3xx_i2c_algo; - - init_waitqueue_head(&adapter_data->waitq); - spin_lock_init(&adapter_data->lock); - - iop3xx_i2c_reset(adapter_data); - iop3xx_i2c_enable(adapter_data); - - platform_set_drvdata(pdev, new_adapter); - new_adapter->algo_data = adapter_data; - - i2c_add_numbered_adapter(new_adapter); - - return 0; - -unmap: - iounmap(adapter_data->ioaddr); - -release_region: - release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); - -free_both: - kfree(adapter_data); - -free_adapter: - kfree(new_adapter); - -out: - return ret; -} - - -static struct platform_driver iop3xx_i2c_driver = { - .probe = iop3xx_i2c_probe, - .remove = iop3xx_i2c_remove, - .driver = { - .owner = THIS_MODULE, - .name = "IOP3xx-I2C", - }, -}; - -module_platform_driver(iop3xx_i2c_driver); - -MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>"); -MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:IOP3xx-I2C"); |