summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c')
-rw-r--r--ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c618
1 files changed, 0 insertions, 618 deletions
diff --git a/ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c b/ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c
deleted file mode 100644
index 2eacb778..00000000
--- a/ANDROID_3.4.5/drivers/i2c/busses/scx200_acb.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- National Semiconductor SCx200 ACCESS.bus support
- Also supports the AMD CS5535 and AMD CS5536
-
- Based on i2c-keywest.c which is:
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-
- 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; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-
-#include <linux/scx200.h>
-
-#define NAME "scx200_acb"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
-MODULE_ALIAS("platform:cs5535-smb");
-MODULE_LICENSE("GPL");
-
-#define MAX_DEVICES 4
-static int base[MAX_DEVICES] = { 0x820, 0x840 };
-module_param_array(base, int, NULL, 0);
-MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
-
-#define POLL_TIMEOUT (HZ/5)
-
-enum scx200_acb_state {
- state_idle,
- state_address,
- state_command,
- state_repeat_start,
- state_quick,
- state_read,
- state_write,
-};
-
-static const char *scx200_acb_state_name[] = {
- "idle",
- "address",
- "command",
- "repeat_start",
- "quick",
- "read",
- "write",
-};
-
-/* Physical interface */
-struct scx200_acb_iface {
- struct scx200_acb_iface *next;
- struct i2c_adapter adapter;
- unsigned base;
- struct mutex mutex;
-
- /* State machine data */
- enum scx200_acb_state state;
- int result;
- u8 address_byte;
- u8 command;
- u8 *ptr;
- char needs_reset;
- unsigned len;
-};
-
-/* Register Definitions */
-#define ACBSDA (iface->base + 0)
-#define ACBST (iface->base + 1)
-#define ACBST_SDAST 0x40 /* SDA Status */
-#define ACBST_BER 0x20
-#define ACBST_NEGACK 0x10 /* Negative Acknowledge */
-#define ACBST_STASTR 0x08 /* Stall After Start */
-#define ACBST_MASTER 0x02
-#define ACBCST (iface->base + 2)
-#define ACBCST_BB 0x02
-#define ACBCTL1 (iface->base + 3)
-#define ACBCTL1_STASTRE 0x80
-#define ACBCTL1_NMINTE 0x40
-#define ACBCTL1_ACK 0x10
-#define ACBCTL1_STOP 0x02
-#define ACBCTL1_START 0x01
-#define ACBADDR (iface->base + 4)
-#define ACBCTL2 (iface->base + 5)
-#define ACBCTL2_ENABLE 0x01
-
-/************************************************************************/
-
-static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
-{
- const char *errmsg;
-
- dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n",
- scx200_acb_state_name[iface->state], status);
-
- if (status & ACBST_BER) {
- errmsg = "bus error";
- goto error;
- }
- if (!(status & ACBST_MASTER)) {
- errmsg = "not master";
- goto error;
- }
- if (status & ACBST_NEGACK) {
- dev_dbg(&iface->adapter.dev, "negative ack in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -ENXIO;
-
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
-
- /* Reset the status register */
- outb(0, ACBST);
- return;
- }
-
- switch (iface->state) {
- case state_idle:
- dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
- break;
-
- case state_address:
- /* Do a pointer write first */
- outb(iface->address_byte & ~1, ACBSDA);
-
- iface->state = state_command;
- break;
-
- case state_command:
- outb(iface->command, ACBSDA);
-
- if (iface->address_byte & 1)
- iface->state = state_repeat_start;
- else
- iface->state = state_write;
- break;
-
- case state_repeat_start:
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
- /* fallthrough */
-
- case state_quick:
- if (iface->address_byte & 1) {
- if (iface->len == 1)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_read;
- } else {
- outb(iface->address_byte, ACBSDA);
-
- iface->state = state_write;
- }
- break;
-
- case state_read:
- /* Set ACK if _next_ byte will be the last one */
- if (iface->len == 2)
- outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
- else
- outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
-
- if (iface->len == 1) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- }
-
- *iface->ptr++ = inb(ACBSDA);
- --iface->len;
-
- break;
-
- case state_write:
- if (iface->len == 0) {
- iface->result = 0;
- iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- break;
- }
-
- outb(*iface->ptr++, ACBSDA);
- --iface->len;
-
- break;
- }
-
- return;
-
- error:
- dev_err(&iface->adapter.dev,
- "%s in state %s (addr=0x%02x, len=%d, status=0x%02x)\n", errmsg,
- scx200_acb_state_name[iface->state], iface->address_byte,
- iface->len, status);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-static void scx200_acb_poll(struct scx200_acb_iface *iface)
-{
- u8 status;
- unsigned long timeout;
-
- timeout = jiffies + POLL_TIMEOUT;
- while (1) {
- status = inb(ACBST);
-
- /* Reset the status register to avoid the hang */
- outb(0, ACBST);
-
- if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
- scx200_acb_machine(iface, status);
- return;
- }
- if (time_after(jiffies, timeout))
- break;
- cpu_relax();
- cond_resched();
- }
-
- dev_err(&iface->adapter.dev, "timeout in state %s\n",
- scx200_acb_state_name[iface->state]);
-
- iface->state = state_idle;
- iface->result = -EIO;
- iface->needs_reset = 1;
-}
-
-static void scx200_acb_reset(struct scx200_acb_iface *iface)
-{
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
- /* Polling mode */
- outb(0, ACBCTL1);
- /* Disable slave address */
- outb(0, ACBADDR);
- /* Enable the ACCESS.bus device */
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
- /* Free STALL after START */
- outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
- /* Send a STOP */
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
- /* Clear BER, NEGACK and STASTR bits */
- outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
- /* Clear BB bit */
- outb(inb(ACBCST) | ACBCST_BB, ACBCST);
-}
-
-static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
- u16 address, unsigned short flags,
- char rw, u8 command, int size,
- union i2c_smbus_data *data)
-{
- struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
- int len;
- u8 *buffer;
- u16 cur_word;
- int rc;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- break;
-
- case I2C_SMBUS_BYTE:
- len = 1;
- buffer = rw ? &data->byte : &command;
- break;
-
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- break;
-
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- break;
-
- case I2C_SMBUS_I2C_BLOCK_DATA:
- len = data->block[0];
- if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
- return -EINVAL;
- buffer = &data->block[1];
- break;
-
- default:
- return -EINVAL;
- }
-
- dev_dbg(&adapter->dev,
- "size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
- size, address, command, len, rw);
-
- if (!len && rw == I2C_SMBUS_READ) {
- dev_dbg(&adapter->dev, "zero length read\n");
- return -EINVAL;
- }
-
- mutex_lock(&iface->mutex);
-
- iface->address_byte = (address << 1) | rw;
- iface->command = command;
- iface->ptr = buffer;
- iface->len = len;
- iface->result = -EINVAL;
- iface->needs_reset = 0;
-
- outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
-
- if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
- iface->state = state_quick;
- else
- iface->state = state_address;
-
- while (iface->state != state_idle)
- scx200_acb_poll(iface);
-
- if (iface->needs_reset)
- scx200_acb_reset(iface);
-
- rc = iface->result;
-
- mutex_unlock(&iface->mutex);
-
- if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
-#ifdef DEBUG
- dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
- if (buffer) {
- int i;
- printk(" data:");
- for (i = 0; i < len; ++i)
- printk(" %02x", buffer[i]);
- }
- printk("\n");
-#endif
-
- return rc;
-}
-
-static u32 scx200_acb_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK;
-}
-
-/* For now, we only handle combined mode (smbus) */
-static const struct i2c_algorithm scx200_acb_algorithm = {
- .smbus_xfer = scx200_acb_smbus_xfer,
- .functionality = scx200_acb_func,
-};
-
-static struct scx200_acb_iface *scx200_acb_list;
-static DEFINE_MUTEX(scx200_acb_list_mutex);
-
-static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
-{
- u8 val;
-
- /* Disable the ACCESS.bus device and Configure the SCL
- frequency: 16 clock cycles */
- outb(0x70, ACBCTL2);
-
- if (inb(ACBCTL2) != 0x70) {
- pr_debug(NAME ": ACBCTL2 readback failed\n");
- return -ENXIO;
- }
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if (val) {
- pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n",
- val);
- return -ENXIO;
- }
-
- outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
-
- outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
-
- val = inb(ACBCTL1);
- if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
- pr_debug(NAME ": enabled, but NMINTE won't be set, "
- "ACBCTL1=0x%02x\n", val);
- return -ENXIO;
- }
-
- return 0;
-}
-
-static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
- struct device *dev, int index)
-{
- struct scx200_acb_iface *iface;
- struct i2c_adapter *adapter;
-
- iface = kzalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface) {
- printk(KERN_ERR NAME ": can't allocate memory\n");
- return NULL;
- }
-
- adapter = &iface->adapter;
- i2c_set_adapdata(adapter, iface);
- snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
- adapter->owner = THIS_MODULE;
- adapter->algo = &scx200_acb_algorithm;
- adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- adapter->dev.parent = dev;
-
- mutex_init(&iface->mutex);
-
- return iface;
-}
-
-static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
-{
- struct i2c_adapter *adapter;
- int rc;
-
- adapter = &iface->adapter;
-
- rc = scx200_acb_probe(iface);
- if (rc) {
- printk(KERN_WARNING NAME ": probe failed\n");
- return rc;
- }
-
- scx200_acb_reset(iface);
-
- if (i2c_add_adapter(adapter) < 0) {
- printk(KERN_ERR NAME ": failed to register\n");
- return -ENODEV;
- }
-
- if (!adapter->dev.parent) {
- /* If there's no dev, we're tracking (ISA) ifaces manually */
- mutex_lock(&scx200_acb_list_mutex);
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- mutex_unlock(&scx200_acb_list_mutex);
- }
-
- return 0;
-}
-
-static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
- unsigned long base, int index, struct device *dev)
-{
- struct scx200_acb_iface *iface;
- int rc;
-
- iface = scx200_create_iface(text, dev, index);
-
- if (iface == NULL)
- return NULL;
-
- if (!request_region(base, 8, iface->adapter.name)) {
- printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
- base, base + 8 - 1);
- goto errout_free;
- }
-
- iface->base = base;
- rc = scx200_acb_create(iface);
-
- if (rc == 0)
- return iface;
-
- release_region(base, 8);
- errout_free:
- kfree(iface);
- return NULL;
-}
-
-static int __devinit scx200_probe(struct platform_device *pdev)
-{
- struct scx200_acb_iface *iface;
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't fetch device resource info\n");
- return -ENODEV;
- }
-
- iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
- if (!iface)
- return -EIO;
-
- dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
- iface->adapter.name);
- platform_set_drvdata(pdev, iface);
-
- return 0;
-}
-
-static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
-{
- i2c_del_adapter(&iface->adapter);
- release_region(iface->base, 8);
- kfree(iface);
-}
-
-static int __devexit scx200_remove(struct platform_device *pdev)
-{
- struct scx200_acb_iface *iface;
-
- iface = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
- scx200_cleanup_iface(iface);
-
- return 0;
-}
-
-static struct platform_driver scx200_pci_driver = {
- .driver = {
- .name = "cs5535-smb",
- .owner = THIS_MODULE,
- },
- .probe = scx200_probe,
- .remove = __devexit_p(scx200_remove),
-};
-
-static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
- { 0, }
-};
-
-static __init void scx200_scan_isa(void)
-{
- int i;
-
- if (!pci_dev_present(scx200_isa))
- return;
-
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] == 0)
- continue;
-
- /* XXX: should we care about failures? */
- scx200_create_dev("SCx200", base[i], i, NULL);
- }
-}
-
-static int __init scx200_acb_init(void)
-{
- pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
-
- /* First scan for ISA-based devices */
- scx200_scan_isa(); /* XXX: should we care about errors? */
-
- /* If at least one bus was created, init must succeed */
- if (scx200_acb_list)
- return 0;
-
- /* No ISA devices; register the platform driver for PCI-based devices */
- return platform_driver_register(&scx200_pci_driver);
-}
-
-static void __exit scx200_acb_cleanup(void)
-{
- struct scx200_acb_iface *iface;
-
- platform_driver_unregister(&scx200_pci_driver);
-
- mutex_lock(&scx200_acb_list_mutex);
- while ((iface = scx200_acb_list) != NULL) {
- scx200_acb_list = iface->next;
- mutex_unlock(&scx200_acb_list_mutex);
-
- scx200_cleanup_iface(iface);
-
- mutex_lock(&scx200_acb_list_mutex);
- }
- mutex_unlock(&scx200_acb_list_mutex);
-}
-
-module_init(scx200_acb_init);
-module_exit(scx200_acb_cleanup);