From: Benjamin Herrenschmidt The code in pmac_low_i2c.c is a low level synchronous version of the i2c keywest driver for use by platform code early during boot or during sleep/wakeup cycles to communicate with some motherboard chips, typically clock chips. It wasn't used on g5 until now, which is good because it wasn't 64 bits clean :) This patch fixes it, and also remove the use of udelay() since it can be used for synchronizing the HW timebase, and so must operate when it's frozen (and our implementation of udelay uses that timebase). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton --- 25-akpm/arch/ppc64/kernel/pmac_low_i2c.c | 46 ++++++++++++++++++------------- 1 files changed, 28 insertions(+), 18 deletions(-) diff -puN arch/ppc64/kernel/pmac_low_i2c.c~ppc64-fix-g5-low-level-i2c-code arch/ppc64/kernel/pmac_low_i2c.c --- 25/arch/ppc64/kernel/pmac_low_i2c.c~ppc64-fix-g5-low-level-i2c-code 2004-11-09 00:08:46.525618056 -0800 +++ 25-akpm/arch/ppc64/kernel/pmac_low_i2c.c 2004-11-09 00:08:46.529617448 -0800 @@ -16,9 +16,10 @@ * properties parser */ +#undef DEBUG + #include #include -#include #include #include #include @@ -33,12 +34,12 @@ #define MAX_LOW_I2C_HOST 4 -#if 1 +#ifdef DEBUG #define DBG(x...) do {\ printk(KERN_DEBUG "KW:" x); \ } while(0) #else -#define DBGG(x...) +#define DBG(x...) #endif struct low_i2c_host; @@ -50,11 +51,11 @@ struct low_i2c_host struct device_node *np; /* OF device node */ struct semaphore mutex; /* Access mutex for use by i2c-keywest */ low_i2c_func_t func; /* Access function */ - unsigned is_open : 1; /* Poor man's access control */ + unsigned int is_open : 1; /* Poor man's access control */ int mode; /* Current mode */ int channel; /* Current channel */ int num_channels; /* Number of channels */ - unsigned long base; /* For keywest-i2c, base address */ + void __iomem *base; /* For keywest-i2c, base address */ int bsteps; /* And register stepping */ int speed; /* And speed */ }; @@ -154,14 +155,12 @@ static const char *__kw_state_names[] = static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) { - return in_8(((volatile u8 *)host->base) - + (((unsigned)reg) << host->bsteps)); + return readb(host->base + (((unsigned int)reg) << host->bsteps)); } static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) { - out_8(((volatile u8 *)host->base) - + (((unsigned)reg) << host->bsteps), val); + writeb(val, host->base + (((unsigned)reg) << host->bsteps)); (void)__kw_read_reg(host, reg_subaddr); } @@ -174,14 +173,19 @@ static inline void __kw_write_reg(struct */ static u8 kw_wait_interrupt(struct low_i2c_host* host) { - int i; + int i, j; u8 isr; - for (i = 0; i < 200000; i++) { + for (i = 0; i < 100000; i++) { isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; if (isr != 0) return isr; - udelay(1); + + /* This code is used with the timebase frozen, we cannot rely + * on udelay ! For now, just use a bogus loop + */ + for (j = 1; j < 10000; j++) + mb(); } return isr; } @@ -190,6 +194,8 @@ static int kw_handle_interrupt(struct lo { u8 ack; + DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); + if (isr == 0) { if (state != state_stop) { DBG("KW: Timeout !\n"); @@ -301,11 +307,9 @@ static int keywest_low_i2c_func(struct l break; case pmac_low_i2c_mode_stdsub: mode_reg |= KW_I2C_MODE_STANDARDSUB; - kw_write_reg(reg_subaddr, subaddr); break; case pmac_low_i2c_mode_combined: mode_reg |= KW_I2C_MODE_COMBINED; - kw_write_reg(reg_subaddr, subaddr); break; } @@ -317,6 +321,11 @@ static int keywest_low_i2c_func(struct l /* Set up address and r/w bit */ kw_write_reg(reg_addr, addr); + /* Set up the sub address */ + if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB + || (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*/); kw_write_reg(reg_control, KW_I2C_CTL_XADDR); @@ -333,7 +342,7 @@ static int keywest_low_i2c_func(struct l static void keywest_low_i2c_add(struct device_node *np) { struct low_i2c_host *host = find_low_i2c_host(NULL); - unsigned long *psteps, *prate, steps, aoffset = 0; + u32 *psteps, *prate, steps, aoffset = 0; struct device_node *parent; if (host == NULL) { @@ -345,7 +354,7 @@ static void keywest_low_i2c_add(struct d init_MUTEX(&host->mutex); host->np = of_node_get(np); - psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL); + psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); steps = psteps ? (*psteps) : 0x10; for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) steps >>= 1; @@ -357,7 +366,7 @@ static void keywest_low_i2c_add(struct d } /* Select interface rate */ host->speed = KW_I2C_MODE_100KHZ; - prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL); + prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); if (prate) switch(*prate) { case 100: host->speed = KW_I2C_MODE_100KHZ; @@ -369,8 +378,9 @@ static void keywest_low_i2c_add(struct d host->speed = KW_I2C_MODE_25KHZ; break; } + host->mode = pmac_low_i2c_mode_std; - host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset, + host->base = ioremap(np->addrs[0].address + aoffset, np->addrs[0].size); host->func = keywest_low_i2c_func; } _