aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c318
-rw-r--r--arch/powerpc/platforms/powermac/setup.c18
-rw-r--r--drivers/i2c/busses/Kconfig24
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-keywest.c754
-rw-r--r--drivers/i2c/busses/i2c-keywest.h108
-rw-r--r--drivers/i2c/busses/i2c-pmac-smu.c324
-rw-r--r--drivers/i2c/busses/i2c-powermac.c290
-rw-r--r--drivers/macintosh/Kconfig10
-rw-r--r--drivers/macintosh/smu.c26
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c50
-rw-r--r--include/asm-powerpc/pmac_low_i2c.h2
12 files changed, 563 insertions, 1364 deletions
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index f31d6a678b9..a25e447f907 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -39,6 +39,10 @@
#include <linux/pmu.h>
#include <linux/delay.h>
#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/timer.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
@@ -63,6 +67,9 @@
#define DBG_LOW(x...)
#endif
+
+static int pmac_i2c_force_poll = 1;
+
/*
* A bus structure. Each bus in the system has such a structure associated.
*/
@@ -80,6 +87,7 @@ struct pmac_i2c_bus
struct semaphore sem;
int opened;
int polled; /* open mode */
+ struct platform_device *platform_dev;
/* ops */
int (*open)(struct pmac_i2c_bus *bus);
@@ -101,6 +109,16 @@ struct pmac_i2c_host_kw
void __iomem *base; /* register base address */
int bsteps; /* register stepping */
int speed; /* speed */
+ int irq;
+ u8 *data;
+ unsigned len;
+ int state;
+ int rw;
+ int polled;
+ int result;
+ struct completion complete;
+ spinlock_t lock;
+ struct timer_list timeout_timer;
};
/* Register indices */
@@ -115,6 +133,8 @@ typedef enum {
reg_data
} reg_t;
+/* The Tumbler audio equalizer can be really slow sometimes */
+#define KW_POLL_TIMEOUT (2*HZ)
/* Mode register */
#define KW_I2C_MODE_100KHZ 0x00
@@ -158,8 +178,9 @@ enum {
};
#define WRONG_STATE(name) do {\
- printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
- name, __kw_state_names[state], isr); \
+ printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \
+ "(isr: %02x)\n", \
+ name, __kw_state_names[host->state], isr); \
} while(0)
static const char *__kw_state_names[] = {
@@ -171,23 +192,22 @@ static const char *__kw_state_names[] = {
"state_dead"
};
-static inline u8 __kw_read_reg(struct pmac_i2c_bus *bus, reg_t reg)
+static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg)
{
- struct pmac_i2c_host_kw *host = bus->hostdata;
return readb(host->base + (((unsigned int)reg) << host->bsteps));
}
-static inline void __kw_write_reg(struct pmac_i2c_bus *bus, reg_t reg, u8 val)
+static inline void __kw_write_reg(struct pmac_i2c_host_kw *host,
+ reg_t reg, u8 val)
{
- struct pmac_i2c_host_kw *host = bus->hostdata;
writeb(val, host->base + (((unsigned)reg) << host->bsteps));
- (void)__kw_read_reg(bus, reg_subaddr);
+ (void)__kw_read_reg(host, reg_subaddr);
}
-#define kw_write_reg(reg, val) __kw_write_reg(bus, reg, val)
-#define kw_read_reg(reg) __kw_read_reg(bus, reg)
+#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
+#define kw_read_reg(reg) __kw_read_reg(host, reg)
-static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus)
+static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host)
{
int i, j;
u8 isr;
@@ -201,8 +221,8 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus)
* on udelay nor schedule when in polled mode !
* For now, just use a bogus loop....
*/
- if (bus->polled) {
- for (j = 1; j < 1000000; j++)
+ if (host->polled) {
+ for (j = 1; j < 100000; j++)
mb();
} else
msleep(1);
@@ -210,86 +230,99 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus)
return isr;
}
-static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw,
- int *rc, u8 **data, int *len, u8 isr)
+static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
{
u8 ack;
DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n",
- __kw_state_names[state], isr);
+ __kw_state_names[host->state], isr);
+
+ if (host->state == state_idle) {
+ printk(KERN_WARNING "low_i2c: Keywest got an out of state"
+ " interrupt, ignoring\n");
+ kw_write_reg(reg_isr, isr);
+ return;
+ }
if (isr == 0) {
- if (state != state_stop) {
+ if (host->state != state_stop) {
DBG_LOW("KW: Timeout !\n");
- *rc = -EIO;
+ host->result = -EIO;
goto stop;
}
- if (state == state_stop) {
+ if (host->state == state_stop) {
ack = kw_read_reg(reg_status);
- if (!(ack & KW_I2C_STAT_BUSY)) {
- state = state_idle;
- kw_write_reg(reg_ier, 0x00);
- }
+ if (ack & KW_I2C_STAT_BUSY)
+ kw_write_reg(reg_status, 0);
+ host->state = state_idle;
+ kw_write_reg(reg_ier, 0x00);
+ if (!host->polled)
+ complete(&host->complete);
}
- return state;
+ return;
}
if (isr & KW_I2C_IRQ_ADDR) {
ack = kw_read_reg(reg_status);
- if (state != state_addr) {
+ if (host->state != state_addr) {
kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
WRONG_STATE("KW_I2C_IRQ_ADDR");
- *rc = -EIO;
+ host->result = -EIO;
goto stop;
}
if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- *rc = -ENODEV;
+ host->result = -ENODEV;
DBG_LOW("KW: NAK on address\n");
- return state_stop;
+ host->state = state_stop;
+ return;
} else {
- if (rw) {
- state = state_read;
- if (*len > 1)
+ if (host->len == 0) {
+ kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+ goto stop;
+ }
+ if (host->rw) {
+ host->state = state_read;
+ if (host->len > 1)
kw_write_reg(reg_control,
KW_I2C_CTL_AAK);
} else {
- state = state_write;
- kw_write_reg(reg_data, **data);
- (*data)++; (*len)--;
+ host->state = state_write;
+ kw_write_reg(reg_data, *(host->data++));
+ host->len--;
}
}
kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
}
if (isr & KW_I2C_IRQ_DATA) {
- if (state == state_read) {
- **data = kw_read_reg(reg_data);
- (*data)++; (*len)--;
+ if (host->state == state_read) {
+ *(host->data++) = kw_read_reg(reg_data);
+ host->len--;
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
- if ((*len) == 0)
- state = state_stop;
- else if ((*len) == 1)
+ if (host->len == 0)
+ host->state = state_stop;
+ else if (host->len == 1)
kw_write_reg(reg_control, 0);
- } else if (state == state_write) {
+ } else if (host->state == state_write) {
ack = kw_read_reg(reg_status);
if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
DBG_LOW("KW: nack on data write\n");
- *rc = -EIO;
+ host->result = -EIO;
goto stop;
- } else if (*len) {
- kw_write_reg(reg_data, **data);
- (*data)++; (*len)--;
+ } else if (host->len) {
+ kw_write_reg(reg_data, *(host->data++));
+ host->len--;
} else {
kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- state = state_stop;
- *rc = 0;
+ host->state = state_stop;
+ host->result = 0;
}
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
} else {
kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
WRONG_STATE("KW_I2C_IRQ_DATA");
- if (state != state_stop) {
- *rc = -EIO;
+ if (host->state != state_stop) {
+ host->result = -EIO;
goto stop;
}
}
@@ -297,21 +330,54 @@ static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw,
if (isr & KW_I2C_IRQ_STOP) {
kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
- if (state != state_stop) {
+ if (host->state != state_stop) {
WRONG_STATE("KW_I2C_IRQ_STOP");
- *rc = -EIO;
+ host->result = -EIO;
}
- return state_idle;
+ host->state = state_idle;
+ if (!host->polled)
+ complete(&host->complete);
}
if (isr & KW_I2C_IRQ_START)
kw_write_reg(reg_isr, KW_I2C_IRQ_START);
- return state;
-
+ return;
stop:
kw_write_reg(reg_control, KW_I2C_CTL_STOP);
- return state_stop;
+ host->state = state_stop;
+ return;
+}
+
+/* Interrupt handler */
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pmac_i2c_host_kw *host = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ del_timer(&host->timeout_timer);
+ kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+ if (host->state != state_idle) {
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void kw_i2c_timeout(unsigned long data)
+{
+ struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr));
+ if (host->state != state_idle) {
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
}
static int kw_i2c_open(struct pmac_i2c_bus *bus)
@@ -332,8 +398,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
{
struct pmac_i2c_host_kw *host = bus->hostdata;
u8 mode_reg = host->speed;
- int state = state_addr;
- int rc = 0;
+ int use_irq = host->irq != NO_IRQ && !bus->polled;
/* Setup mode & subaddress if any */
switch(bus->mode) {
@@ -371,18 +436,50 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
|| (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
kw_write_reg(reg_subaddr, subaddr);
- /* Start sending address & disable interrupt*/
- kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+ /* Prepare for async operations */
+ host->data = data;
+ host->len = len;
+ host->state = state_addr;
+ host->result = 0;
+ host->rw = (addrdir & 1);
+ host->polled = bus->polled;
+
+ /* Enable interrupt if not using polled mode and interrupt is
+ * available
+ */
+ if (use_irq) {
+ /* Clear completion */
+ INIT_COMPLETION(host->complete);
+ /* Ack stale interrupts */
+ kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+ /* Arm timeout */
+ host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT;
+ add_timer(&host->timeout_timer);
+ /* Enable emission */
+ kw_write_reg(reg_ier, KW_I2C_IRQ_MASK);
+ }
+
+ /* Start sending address */
kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
- /* State machine, to turn into an interrupt handler in the future */
- while(state != state_idle) {
- u8 isr = kw_i2c_wait_interrupt(bus);
- state = kw_i2c_handle_interrupt(bus, state, addrdir & 1, &rc,
- &data, &len, isr);
+ /* Wait for completion */
+ if (use_irq)
+ wait_for_completion(&host->complete);
+ else {
+ while(host->state != state_idle) {
+ unsigned long flags;
+
+ u8 isr = kw_i2c_wait_interrupt(host);
+ spin_lock_irqsave(&host->lock, flags);
+ kw_i2c_handle_interrupt(host, isr);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
}
- return rc;
+ /* Disable emission */
+ kw_write_reg(reg_ier, 0);
+
+ return host->result;
}
static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
@@ -409,6 +506,12 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
return NULL;
}
init_MUTEX(&host->mutex);
+ init_completion(&host->complete);
+ spin_lock_init(&host->lock);
+ init_timer(&host->timeout_timer);
+ host->timeout_timer.function = kw_i2c_timeout;
+ host->timeout_timer.data = (unsigned long)host;
+
psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
steps = psteps ? (*psteps) : 0x10;
for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
@@ -427,9 +530,28 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
host->speed = KW_I2C_MODE_25KHZ;
break;
}
+ if (np->n_intrs > 0)
+ host->irq = np->intrs[0].line;
+ else
+ host->irq = NO_IRQ;
- printk(KERN_INFO "KeyWest i2c @0x%08x %s\n", *addrp, np->full_name);
host->base = ioremap((*addrp), 0x1000);
+ if (host->base == NULL) {
+ printk(KERN_ERR "low_i2c: Can't map registers for %s\n",
+ np->full_name);
+ kfree(host);
+ return NULL;
+ }
+
+ /* Make sure IRA is disabled */
+ kw_write_reg(reg_ier, 0);
+
+ /* Request chip interrupt */
+ if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host))
+ host->irq = NO_IRQ;
+
+ printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
+ *addrp, host->irq, np->full_name);
return host;
}
@@ -591,7 +713,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
req->nbytes = sizeof(struct pmu_i2c_hdr) + 1;
req->done = pmu_i2c_complete;
req->arg = &comp;
- if (!read) {
+ if (!read && len) {
memcpy(hdr->data, data, len);
req->nbytes += len;
}
@@ -637,7 +759,8 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
" bytes, expected %d !\n", rlen, len);
return -EIO;
}
- memcpy(data, &req->reply[1], len);
+ if (len)
+ memcpy(data, &req->reply[1], len);
return 0;
}
}
@@ -713,6 +836,10 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
int read = addrdir & 1;
int rc = 0;
+ if ((read && len > SMU_I2C_READ_MAX) ||
+ ((!read) && len > SMU_I2C_WRITE_MAX))
+ return -EINVAL;
+
memset(cmd, 0, sizeof(struct smu_i2c_cmd));
cmd->info.bus = bus->channel;
cmd->info.devaddr = addrdir;
@@ -740,7 +867,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
default:
return -EINVAL;
}
- if (!read)
+ if (!read && len)
memcpy(cmd->info.data, data, len);
init_completion(&comp);
@@ -752,7 +879,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
wait_for_completion(&comp);
rc = cmd->status;
- if (read)
+ if (read && len)
memcpy(data, cmd->info.data, len);
return rc < 0 ? rc : 0;
}
@@ -767,7 +894,7 @@ static void __init smu_i2c_probe(void)
if (!smu_present())
return;
- controller = of_find_node_by_name(NULL, "smu_i2c_control");
+ controller = of_find_node_by_name(NULL, "smu-i2c-control");
if (controller == NULL)
controller = of_find_node_by_name(NULL, "smu");
if (controller == NULL)
@@ -884,6 +1011,13 @@ int pmac_i2c_get_flags(struct pmac_i2c_bus *bus)
}
EXPORT_SYMBOL_GPL(pmac_i2c_get_flags);
+int pmac_i2c_get_channel(struct pmac_i2c_bus *bus)
+{
+ return bus->channel;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_get_channel);
+
+
void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus,
struct i2c_adapter *adapter)
{
@@ -906,6 +1040,17 @@ struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus)
}
EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter);
+struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter)
+{
+ struct pmac_i2c_bus *bus;
+
+ list_for_each_entry(bus, &pmac_i2c_busses, link)
+ if (bus->adapter == adapter)
+ return bus;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus);
+
extern int pmac_i2c_match_adapter(struct device_node *dev,
struct i2c_adapter *adapter)
{
@@ -956,7 +1101,7 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
int rc;
down(&bus->sem);
- bus->polled = polled;
+ bus->polled = polled || pmac_i2c_force_poll;
bus->opened = 1;
bus->mode = pmac_i2c_mode_std;
if (bus->open && (rc = bus->open(bus)) != 0) {
@@ -1034,14 +1179,43 @@ int __init pmac_i2c_init(void)
kw_i2c_probe();
#ifdef CONFIG_ADB_PMU
+ /* Probe PMU i2c busses */
pmu_i2c_probe();
#endif
#ifdef CONFIG_PMAC_SMU
+ /* Probe SMU i2c busses */
smu_i2c_probe();
#endif
-
return 0;
}
arch_initcall(pmac_i2c_init);
+/* Since pmac_i2c_init can be called too early for the platform device
+ * registration, we need to do it at a later time. In our case, subsys
+ * happens to fit well, though I agree it's a bit of a hack...
+ */
+static int __init pmac_i2c_create_platform_devices(void)
+{
+ struct pmac_i2c_bus *bus;
+ int i = 0;
+
+ /* In the case where we are initialized from smp_init(), we must
+ * not use the timer (and thus the irq). It's safe from now on
+ * though
+ */
+ pmac_i2c_force_poll = 0;
+
+ /* Create platform devices */
+ list_for_each_entry(bus, &pmac_i2c_busses, link) {
+ bus->platform_dev =
+ platform_device_alloc("i2c-powermac", i++);
+ if (bus->platform_dev == NULL)
+ return -ENOMEM;
+ bus->platform_dev->dev.platform_data = bus;
+ platform_device_add(bus->platform_dev);
+ }
+
+ return 0;
+}
+subsys_initcall(pmac_i2c_create_platform_devices);
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index dc5cdc1484e..3b1a9d4fcbc 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -650,7 +650,7 @@ static int pmac_check_legacy_ioport(unsigned int baseport)
static int __init pmac_declare_of_platform_devices(void)
{
- struct device_node *np, *npp;
+ struct device_node *np;
np = of_find_node_by_name(NULL, "valkyrie");
if (np)
@@ -658,22 +658,6 @@ static int __init pmac_declare_of_platform_devices(void)
np = of_find_node_by_name(NULL, "platinum");
if (np)
of_platform_device_create(np, "platinum", NULL);
- npp = of_find_node_by_name(NULL, "uni-n");
- if (npp == NULL)
- npp = of_find_node_by_name(NULL, "u3");
- if (npp == NULL)
- npp = of_find_node_by_name(NULL, "u4");
- if (npp) {
- for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) {
- if (strncmp(np->name, "i2c", 3) == 0) {
- of_platform_device_create(np, "uni-n-i2c",
- NULL);
- of_node_put(np);
- break;
- }
- }
- of_node_put(npp);
- }
np = of_find_node_by_type(NULL, "smu");
if (np) {
of_platform_device_create(np, "smu", NULL);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4010fe92e72..08d5b8fed2d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -236,27 +236,17 @@ config I2C_IXP2000
This support is also available as a module. If so, the module
will be called i2c-ixp2000.
-config I2C_KEYWEST
- tristate "Powermac Keywest I2C interface"
+config I2C_POWERMAC
+ tristate "Powermac I2C interface"
depends on I2C && PPC_PMAC
+ default y
help
- This supports the use of the I2C interface in the combo-I/O
- chip on recent Apple machines. Say Y if you have such a machine.
-
- This support is also available as a module. If so, the module
- will be called i2c-keywest.
-
-config I2C_PMAC_SMU
- tristate "Powermac SMU I2C interface"
- depends on I2C && PMAC_SMU
- help
- This supports the use of the I2C interface in the SMU
- chip on recent Apple machines like the iMac G5. It is used
- among others by the thermal control driver for those machines.
- Say Y if you have such a machine.
+ This exposes the various PowerMac i2c interfaces to the linux i2c
+ layer and to userland. It is used by various drivers on the powemac
+ platform, thus should generally be enabled.
This support is also available as a module. If so, the module
- will be called i2c-pmac-smu.
+ will be called i2c-powermac.
config I2C_MPC
tristate "MPC107/824x/85xx/52xx"
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index f1df00f66c6..b44831dff68 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -19,8 +19,7 @@ obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_ITE) += i2c-ite.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
-obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o
-obj-$(CONFIG_I2C_PMAC_SMU) += i2c-pmac-smu.o
+obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
deleted file mode 100644
index 93e7080e3bc..00000000000
--- a/drivers/i2c/busses/i2c-keywest.c
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- i2c Support for Apple Keywest I2C Bus Controller
-
- Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
-
- Original work by
-
- 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.
-
- Changes:
-
- 2001/12/13 BenH New implementation
- 2001/12/15 BenH Add support for "byte" and "quick"
- transfers. Add i2c_xfer routine.
- 2003/09/21 BenH Rework state machine with Paulus help
- 2004/01/21 BenH Merge in Greg KH changes, polled mode is back
- 2004/02/05 BenH Merge 64 bits fixes from the g5 ppc64 tree
-
- My understanding of the various modes supported by keywest are:
-
- - Dumb mode : not implemented, probably direct tweaking of lines
- - Standard mode : simple i2c transaction of type
- S Addr R/W A Data A Data ... T
- - Standard sub mode : combined 8 bit subaddr write with data read
- S Addr R/W A SubAddr A Data A Data ... T
- - Combined mode : Subaddress and Data sequences appended with no stop
- S Addr R/W A SubAddr S Addr R/W A Data A Data ... T
-
- Currently, this driver uses only Standard mode for i2c xfer, and
- smbus byte & quick transfers ; and uses StandardSub mode for
- other smbus transfers instead of combined as we need that for the
- sound driver to be happy
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pmac_low_i2c.h>
-
-#include "i2c-keywest.h"
-
-#undef POLLED_MODE
-
-/* Some debug macros */
-#define WRONG_STATE(name) do {\
- pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
- name, __kw_state_names[iface->state], isr); \
- } while(0)
-
-#ifdef DEBUG
-static const char *__kw_state_names[] = {
- "state_idle",
- "state_addr",
- "state_read",
- "state_write",
- "state_stop",
- "state_dead"
-};
-#endif /* DEBUG */
-
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
-MODULE_LICENSE("GPL");
-
-#ifdef POLLED_MODE
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8
-wait_interrupt(struct keywest_iface* iface)
-{
- int i;
- u8 isr;
-
- for (i = 0; i < 200000; i++) {
- isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
- if (isr != 0)
- return isr;
- udelay(10);
- }
- return isr;
-}
-#endif /* POLLED_MODE */
-
-static void
-do_stop(struct keywest_iface* iface, int result)
-{
- write_reg(reg_control, KW_I2C_CTL_STOP);
- iface->state = state_stop;
- iface->result = result;
-}
-
-/* Main state machine for standard & standard sub mode */
-static void
-handle_interrupt(struct keywest_iface *iface, u8 isr)
-{
- int ack;
-
- if (isr == 0) {
- if (iface->state != state_stop) {
- pr_debug("KW: Timeout !\n");
- do_stop(iface, -EIO);
- }
- if (iface->state == state_stop) {
- ack = read_reg(reg_status);
- if (!(ack & KW_I2C_STAT_BUSY)) {
- iface->state = state_idle;
- write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
- complete(&iface->complete);
-#endif /* POLLED_MODE */
- }
- }
- return;
- }
-
- if (isr & KW_I2C_IRQ_ADDR) {
- ack = read_reg(reg_status);
- if (iface->state != state_addr) {
- write_reg(reg_isr, KW_I2C_IRQ_ADDR);
- WRONG_STATE("KW_I2C_IRQ_ADDR");
- do_stop(iface, -EIO);
- return;
- }
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- iface->state = state_stop;
- iface->result = -ENODEV;
- pr_debug("KW: NAK on address\n");
- } else {
- /* Handle rw "quick" mode */
- if (iface->datalen == 0) {
- do_stop(iface, 0);
- } else if (iface->read_write == I2C_SMBUS_READ) {
- iface->state = state_read;
- if (iface->datalen > 1)
- write_reg(reg_control, KW_I2C_CTL_AAK);
- } else {
- iface->state = state_write;
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- }
- }
- write_reg(reg_isr, KW_I2C_IRQ_ADDR);
- }
-
- if (isr & KW_I2C_IRQ_DATA) {
- if (iface->state == state_read) {
- *(iface->data++) = read_reg(reg_data);
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- iface->datalen--;
- if (iface->datalen == 0)
- iface->state = state_stop;
- else if (iface->datalen == 1)
- write_reg(reg_control, 0);
- } else if (iface->state == state_write) {
- /* Check ack status */
- ack = read_reg(reg_status);
- if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
- pr_debug("KW: nack on data write (%x): %x\n",
- iface->data[-1], ack);
- do_stop(iface, -EIO);
- } else if (iface->datalen) {
- write_reg(reg_data, *(iface->data++));
- iface->datalen--;
- } else {
- write_reg(reg_control, KW_I2C_CTL_STOP);
- iface->state = state_stop;
- iface->result = 0;
- }
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- } else {
- write_reg(reg_isr, KW_I2C_IRQ_DATA);
- WRONG_STATE("KW_I2C_IRQ_DATA");
- if (iface->state != state_stop)
- do_stop(iface, -EIO);
- }
- }
-
- if (isr & KW_I2C_IRQ_STOP) {
- write_reg(reg_isr, KW_I2C_IRQ_STOP);
- if (iface->state != state_stop) {
- WRONG_STATE("KW_I2C_IRQ_STOP");
- iface->result = -EIO;
- }
- iface->state = state_idle;
- write_reg(reg_ier, 0x00);
-#ifndef POLLED_MODE
- complete(&iface->complete);
-#endif /* POLLED_MODE */
- }
-
- if (isr & KW_I2C_IRQ_START)
- write_reg(reg_isr, KW_I2C_IRQ_START);
-}
-
-#ifndef POLLED_MODE
-
-/* Interrupt handler */
-static irqreturn_t
-keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct keywest_iface *iface = (struct keywest_iface *)dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(&iface->lock, flags);
- del_timer(&iface->timeout_timer);
- handle_interrupt(iface, read_reg(reg_isr));
- if (iface->state != state_idle) {
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
- }
- spin_unlock_irqrestore(&iface->lock, flags);
- return IRQ_HANDLED;
-}
-
-static void
-keywest_timeout(unsigned long data)
-{
- struct keywest_iface *iface = (struct keywest_iface *)data;
- unsigned long flags;
-
- pr_debug("timeout !\n");
- spin_lock_irqsave(&iface->lock, flags);
- handle_interrupt(iface, read_reg(reg_isr));
- if (iface->state != state_idle) {
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
- }
- spin_unlock_irqrestore(&iface->lock, flags);
-}
-
-#endif /* POLLED_MODE */
-
-/*
- * SMBUS-type transfer entrypoint
- */
-static s32
-keywest_smbus_xfer( struct i2c_adapter* adap,
- u16 addr,
- unsigned short flags,
- char read_write,
- u8 command,
- int size,
- union i2c_smbus_data* data)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
- int len;
- u8* buffer;
- u16 cur_word;
- int rc = 0;
-
- if (iface->state == state_dead)
- return -ENXIO;
-
- /* Prepare datas & select mode */
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- switch (size) {
- case I2C_SMBUS_QUICK:
- len = 0;
- buffer = NULL;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARD;
- break;
- case I2C_SMBUS_BYTE_DATA:
- len = 1;
- buffer = &data->byte;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_WORD_DATA:
- len = 2;
- cur_word = cpu_to_le16(data->word);
- buffer = (u8 *)&cur_word;
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- len = data->block[0];
- buffer = &data->block[1];
- iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
- break;
- default:
- return -1;
- }
-
- /* Turn a standardsub read into a combined mode access */
- if (read_write == I2C_SMBUS_READ
- && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) {
- iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
- iface->cur_mode |= KW_I2C_MODE_COMBINED;
- }
-
- /* Original driver had this limitation */
- if (len > 32)
- len = 32;
-
- if (pmac_low_i2c_lock(iface->node))
- return -ENXIO;
-
- pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
- chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
-
- iface->data = buffer;
- iface->datalen = len;
- iface->state = state_addr;
- iface->result = 0;
- iface->read_write = read_write;
-
- /* Setup channel & clear pending irqs */
- write_reg(reg_isr, read_reg(reg_isr));
- write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
- write_reg(reg_status, 0);
-
- /* Set up address and r/w bit */
- write_reg(reg_addr,
- (addr << 1) | ((read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
-
- /* Set up the sub address */
- if ((iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
- || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
- write_reg(reg_subaddr, command);
-
-#ifndef POLLED_MODE
- /* Arm timeout */
- iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
- add_timer(&iface->timeout_timer);
-#endif
-
- /* Start sending address & enable interrupt*/
- write_reg(reg_control, KW_I2C_CTL_XADDR);
- write_reg(reg_ier, KW_I2C_IRQ_MASK);
-
-#ifdef POLLED_MODE
- pr_debug("using polled mode...\n");
- /* State machine, to turn into an interrupt handler */
- while(iface->state != state_idle) {
- unsigned long flags;
-
- u8 isr = wait_interrupt(iface);
- spin_lock_irqsave(&iface->lock, flags);
- handle_interrupt(iface, isr);
- spin_unlock_irqrestore(&iface->lock, flags);
- }
-#else /* POLLED_MODE */
- pr_debug("using interrupt mode...\n");
- wait_for_completion(&iface->complete);
-#endif /* POLLED_MODE */
-
- rc = iface->result;
- pr_debug("transfer done, result: %d\n", rc);
-
- if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ)
- data->word = le16_to_cpu(cur_word);
-
- /* Release sem */
- pmac_low_i2c_unlock(iface->node);
-
- return rc;
-}
-
-/*
- * Generic i2c master transfer entrypoint
- */
-static int
-keywest_xfer( struct i2c_adapter *adap,
- struct i2c_msg *msgs,
- int num)
-{
- struct keywest_chan* chan = i2c_get_adapdata(adap);
- struct keywest_iface* iface = chan->iface;
-