diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/powermac/low_i2c.c | 318 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/setup.c | 18 |
2 files changed, 247 insertions, 89 deletions
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f31d6a678b9e..a25e447f907f 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c | |||
@@ -39,6 +39,10 @@ | |||
39 | #include <linux/pmu.h> | 39 | #include <linux/pmu.h> |
40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
41 | #include <linux/completion.h> | 41 | #include <linux/completion.h> |
42 | #include <linux/platform_device.h> | ||
43 | #include <linux/interrupt.h> | ||
44 | #include <linux/completion.h> | ||
45 | #include <linux/timer.h> | ||
42 | #include <asm/keylargo.h> | 46 | #include <asm/keylargo.h> |
43 | #include <asm/uninorth.h> | 47 | #include <asm/uninorth.h> |
44 | #include <asm/io.h> | 48 | #include <asm/io.h> |
@@ -63,6 +67,9 @@ | |||
63 | #define DBG_LOW(x...) | 67 | #define DBG_LOW(x...) |
64 | #endif | 68 | #endif |
65 | 69 | ||
70 | |||
71 | static int pmac_i2c_force_poll = 1; | ||
72 | |||
66 | /* | 73 | /* |
67 | * A bus structure. Each bus in the system has such a structure associated. | 74 | * A bus structure. Each bus in the system has such a structure associated. |
68 | */ | 75 | */ |
@@ -80,6 +87,7 @@ struct pmac_i2c_bus | |||
80 | struct semaphore sem; | 87 | struct semaphore sem; |
81 | int opened; | 88 | int opened; |
82 | int polled; /* open mode */ | 89 | int polled; /* open mode */ |
90 | struct platform_device *platform_dev; | ||
83 | 91 | ||
84 | /* ops */ | 92 | /* ops */ |
85 | int (*open)(struct pmac_i2c_bus *bus); | 93 | int (*open)(struct pmac_i2c_bus *bus); |
@@ -101,6 +109,16 @@ struct pmac_i2c_host_kw | |||
101 | void __iomem *base; /* register base address */ | 109 | void __iomem *base; /* register base address */ |
102 | int bsteps; /* register stepping */ | 110 | int bsteps; /* register stepping */ |
103 | int speed; /* speed */ | 111 | int speed; /* speed */ |
112 | int irq; | ||
113 | u8 *data; | ||
114 | unsigned len; | ||
115 | int state; | ||
116 | int rw; | ||
117 | int polled; | ||
118 | int result; | ||
119 | struct completion complete; | ||
120 | spinlock_t lock; | ||
121 | struct timer_list timeout_timer; | ||
104 | }; | 122 | }; |
105 | 123 | ||
106 | /* Register indices */ | 124 | /* Register indices */ |
@@ -115,6 +133,8 @@ typedef enum { | |||
115 | reg_data | 133 | reg_data |
116 | } reg_t; | 134 | } reg_t; |
117 | 135 | ||
136 | /* The Tumbler audio equalizer can be really slow sometimes */ | ||
137 | #define KW_POLL_TIMEOUT (2*HZ) | ||
118 | 138 | ||
119 | /* Mode register */ | 139 | /* Mode register */ |
120 | #define KW_I2C_MODE_100KHZ 0x00 | 140 | #define KW_I2C_MODE_100KHZ 0x00 |
@@ -158,8 +178,9 @@ enum { | |||
158 | }; | 178 | }; |
159 | 179 | ||
160 | #define WRONG_STATE(name) do {\ | 180 | #define WRONG_STATE(name) do {\ |
161 | printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ | 181 | printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \ |
162 | name, __kw_state_names[state], isr); \ | 182 | "(isr: %02x)\n", \ |
183 | name, __kw_state_names[host->state], isr); \ | ||
163 | } while(0) | 184 | } while(0) |
164 | 185 | ||
165 | static const char *__kw_state_names[] = { | 186 | static const char *__kw_state_names[] = { |
@@ -171,23 +192,22 @@ static const char *__kw_state_names[] = { | |||
171 | "state_dead" | 192 | "state_dead" |
172 | }; | 193 | }; |
173 | 194 | ||
174 | static inline u8 __kw_read_reg(struct pmac_i2c_bus *bus, reg_t reg) | 195 | static inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg) |
175 | { | 196 | { |
176 | struct pmac_i2c_host_kw *host = bus->hostdata; | ||
177 | return readb(host->base + (((unsigned int)reg) << host->bsteps)); | 197 | return readb(host->base + (((unsigned int)reg) << host->bsteps)); |
178 | } | 198 | } |
179 | 199 | ||
180 | static inline void __kw_write_reg(struct pmac_i2c_bus *bus, reg_t reg, u8 val) | 200 | static inline void __kw_write_reg(struct pmac_i2c_host_kw *host, |
201 | reg_t reg, u8 val) | ||
181 | { | 202 | { |
182 | struct pmac_i2c_host_kw *host = bus->hostdata; | ||
183 | writeb(val, host->base + (((unsigned)reg) << host->bsteps)); | 203 | writeb(val, host->base + (((unsigned)reg) << host->bsteps)); |
184 | (void)__kw_read_reg(bus, reg_subaddr); | 204 | (void)__kw_read_reg(host, reg_subaddr); |
185 | } | 205 | } |
186 | 206 | ||
187 | #define kw_write_reg(reg, val) __kw_write_reg(bus, reg, val) | 207 | #define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) |
188 | #define kw_read_reg(reg) __kw_read_reg(bus, reg) | 208 | #define kw_read_reg(reg) __kw_read_reg(host, reg) |
189 | 209 | ||
190 | static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) | 210 | static u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host) |
191 | { | 211 | { |
192 | int i, j; | 212 | int i, j; |
193 | u8 isr; | 213 | u8 isr; |
@@ -201,8 +221,8 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) | |||
201 | * on udelay nor schedule when in polled mode ! | 221 | * on udelay nor schedule when in polled mode ! |
202 | * For now, just use a bogus loop.... | 222 | * For now, just use a bogus loop.... |
203 | */ | 223 | */ |
204 | if (bus->polled) { | 224 | if (host->polled) { |
205 | for (j = 1; j < 1000000; j++) | 225 | for (j = 1; j < 100000; j++) |
206 | mb(); | 226 | mb(); |
207 | } else | 227 | } else |
208 | msleep(1); | 228 | msleep(1); |
@@ -210,86 +230,99 @@ static u8 kw_i2c_wait_interrupt(struct pmac_i2c_bus* bus) | |||
210 | return isr; | 230 | return isr; |
211 | } | 231 | } |
212 | 232 | ||
213 | static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw, | 233 | static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr) |
214 | int *rc, u8 **data, int *len, u8 isr) | ||
215 | { | 234 | { |
216 | u8 ack; | 235 | u8 ack; |
217 | 236 | ||
218 | DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n", | 237 | DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n", |
219 | __kw_state_names[state], isr); | 238 | __kw_state_names[host->state], isr); |
239 | |||
240 | if (host->state == state_idle) { | ||
241 | printk(KERN_WARNING "low_i2c: Keywest got an out of state" | ||
242 | " interrupt, ignoring\n"); | ||
243 | kw_write_reg(reg_isr, isr); | ||
244 | return; | ||
245 | } | ||
220 | 246 | ||
221 | if (isr == 0) { | 247 | if (isr == 0) { |
222 | if (state != state_stop) { | 248 | if (host->state != state_stop) { |
223 | DBG_LOW("KW: Timeout !\n"); | 249 | DBG_LOW("KW: Timeout !\n"); |
224 | *rc = -EIO; | 250 | host->result = -EIO; |
225 | goto stop; | 251 | goto stop; |
226 | } | 252 | } |
227 | if (state == state_stop) { | 253 | if (host->state == state_stop) { |
228 | ack = kw_read_reg(reg_status); | 254 | ack = kw_read_reg(reg_status); |
229 | if (!(ack & KW_I2C_STAT_BUSY)) { | 255 | if (ack & KW_I2C_STAT_BUSY) |
230 | state = state_idle; | 256 | kw_write_reg(reg_status, 0); |
231 | kw_write_reg(reg_ier, 0x00); | 257 | host->state = state_idle; |
232 | } | 258 | kw_write_reg(reg_ier, 0x00); |
259 | if (!host->polled) | ||
260 | complete(&host->complete); | ||
233 | } | 261 | } |
234 | return state; | 262 | return; |
235 | } | 263 | } |
236 | 264 | ||
237 | if (isr & KW_I2C_IRQ_ADDR) { | 265 | if (isr & KW_I2C_IRQ_ADDR) { |
238 | ack = kw_read_reg(reg_status); | 266 | ack = kw_read_reg(reg_status); |
239 | if (state != state_addr) { | 267 | if (host->state != state_addr) { |
240 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); | 268 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); |
241 | WRONG_STATE("KW_I2C_IRQ_ADDR"); | 269 | WRONG_STATE("KW_I2C_IRQ_ADDR"); |
242 | *rc = -EIO; | 270 | host->result = -EIO; |
243 | goto stop; | 271 | goto stop; |
244 | } | 272 | } |
245 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { | 273 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { |
246 | *rc = -ENODEV; | 274 | host->result = -ENODEV; |
247 | DBG_LOW("KW: NAK on address\n"); | 275 | DBG_LOW("KW: NAK on address\n"); |
248 | return state_stop; | 276 | host->state = state_stop; |
277 | return; | ||
249 | } else { | 278 | } else { |
250 | if (rw) { | 279 | if (host->len == 0) { |
251 | state = state_read; | 280 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); |
252 | if (*len > 1) | 281 | goto stop; |
282 | } | ||
283 | if (host->rw) { | ||
284 | host->state = state_read; | ||
285 | if (host->len > 1) | ||
253 | kw_write_reg(reg_control, | 286 | kw_write_reg(reg_control, |
254 | KW_I2C_CTL_AAK); | 287 | KW_I2C_CTL_AAK); |
255 | } else { | 288 | } else { |
256 | state = state_write; | 289 | host->state = state_write; |
257 | kw_write_reg(reg_data, **data); | 290 | kw_write_reg(reg_data, *(host->data++)); |
258 | (*data)++; (*len)--; | 291 | host->len--; |
259 | } | 292 | } |
260 | } | 293 | } |
261 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); | 294 | kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); |
262 | } | 295 | } |
263 | 296 | ||
264 | if (isr & KW_I2C_IRQ_DATA) { | 297 | if (isr & KW_I2C_IRQ_DATA) { |
265 | if (state == state_read) { | 298 | if (host->state == state_read) { |
266 | **data = kw_read_reg(reg_data); | 299 | *(host->data++) = kw_read_reg(reg_data); |
267 | (*data)++; (*len)--; | 300 | host->len--; |
268 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | 301 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); |
269 | if ((*len) == 0) | 302 | if (host->len == 0) |
270 | state = state_stop; | 303 | host->state = state_stop; |
271 | else if ((*len) == 1) | 304 | else if (host->len == 1) |
272 | kw_write_reg(reg_control, 0); | 305 | kw_write_reg(reg_control, 0); |
273 | } else if (state == state_write) { | 306 | } else if (host->state == state_write) { |
274 | ack = kw_read_reg(reg_status); | 307 | ack = kw_read_reg(reg_status); |
275 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { | 308 | if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { |
276 | DBG_LOW("KW: nack on data write\n"); | 309 | DBG_LOW("KW: nack on data write\n"); |
277 | *rc = -EIO; | 310 | host->result = -EIO; |
278 | goto stop; | 311 | goto stop; |
279 | } else if (*len) { | 312 | } else if (host->len) { |
280 | kw_write_reg(reg_data, **data); | 313 | kw_write_reg(reg_data, *(host->data++)); |
281 | (*data)++; (*len)--; | 314 | host->len--; |
282 | } else { | 315 | } else { |
283 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); | 316 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); |
284 | state = state_stop; | 317 | host->state = state_stop; |
285 | *rc = 0; | 318 | host->result = 0; |
286 | } | 319 | } |
287 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | 320 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); |
288 | } else { | 321 | } else { |
289 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); | 322 | kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); |
290 | WRONG_STATE("KW_I2C_IRQ_DATA"); | 323 | WRONG_STATE("KW_I2C_IRQ_DATA"); |
291 | if (state != state_stop) { | 324 | if (host->state != state_stop) { |
292 | *rc = -EIO; | 325 | host->result = -EIO; |
293 | goto stop; | 326 | goto stop; |
294 | } | 327 | } |
295 | } | 328 | } |
@@ -297,21 +330,54 @@ static int kw_i2c_handle_interrupt(struct pmac_i2c_bus *bus, int state, int rw, | |||
297 | 330 | ||
298 | if (isr & KW_I2C_IRQ_STOP) { | 331 | if (isr & KW_I2C_IRQ_STOP) { |
299 | kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); | 332 | kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); |
300 | if (state != state_stop) { | 333 | if (host->state != state_stop) { |
301 | WRONG_STATE("KW_I2C_IRQ_STOP"); | 334 | WRONG_STATE("KW_I2C_IRQ_STOP"); |
302 | *rc = -EIO; | 335 | host->result = -EIO; |
303 | } | 336 | } |
304 | return state_idle; | 337 | host->state = state_idle; |
338 | if (!host->polled) | ||
339 | complete(&host->complete); | ||
305 | } | 340 | } |
306 | 341 | ||
307 | if (isr & KW_I2C_IRQ_START) | 342 | if (isr & KW_I2C_IRQ_START) |
308 | kw_write_reg(reg_isr, KW_I2C_IRQ_START); | 343 | kw_write_reg(reg_isr, KW_I2C_IRQ_START); |
309 | 344 | ||
310 | return state; | 345 | return; |
311 | |||
312 | stop: | 346 | stop: |
313 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); | 347 | kw_write_reg(reg_control, KW_I2C_CTL_STOP); |
314 | return state_stop; | 348 | host->state = state_stop; |
349 | return; | ||
350 | } | ||
351 | |||
352 | /* Interrupt handler */ | ||
353 | static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
354 | { | ||
355 | struct pmac_i2c_host_kw *host = dev_id; | ||
356 | unsigned long flags; | ||
357 | |||
358 | spin_lock_irqsave(&host->lock, flags); | ||
359 | del_timer(&host->timeout_timer); | ||
360 | kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); | ||
361 | if (host->state != state_idle) { | ||
362 | host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; | ||
363 | add_timer(&host->timeout_timer); | ||
364 | } | ||
365 | spin_unlock_irqrestore(&host->lock, flags); | ||
366 | return IRQ_HANDLED; | ||
367 | } | ||
368 | |||
369 | static void kw_i2c_timeout(unsigned long data) | ||
370 | { | ||
371 | struct pmac_i2c_host_kw *host = (struct pmac_i2c_host_kw *)data; | ||
372 | unsigned long flags; | ||
373 | |||
374 | spin_lock_irqsave(&host->lock, flags); | ||
375 | kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); | ||
376 | if (host->state != state_idle) { | ||
377 | host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; | ||
378 | add_timer(&host->timeout_timer); | ||
379 | } | ||
380 | spin_unlock_irqrestore(&host->lock, flags); | ||
315 | } | 381 | } |
316 | 382 | ||
317 | static int kw_i2c_open(struct pmac_i2c_bus *bus) | 383 | 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, | |||
332 | { | 398 | { |
333 | struct pmac_i2c_host_kw *host = bus->hostdata; | 399 | struct pmac_i2c_host_kw *host = bus->hostdata; |
334 | u8 mode_reg = host->speed; | 400 | u8 mode_reg = host->speed; |
335 | int state = state_addr; | 401 | int use_irq = host->irq != NO_IRQ && !bus->polled; |
336 | int rc = 0; | ||
337 | 402 | ||
338 | /* Setup mode & subaddress if any */ | 403 | /* Setup mode & subaddress if any */ |
339 | switch(bus->mode) { | 404 | switch(bus->mode) { |
@@ -371,18 +436,50 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
371 | || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) | 436 | || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) |
372 | kw_write_reg(reg_subaddr, subaddr); | 437 | kw_write_reg(reg_subaddr, subaddr); |
373 | 438 | ||
374 | /* Start sending address & disable interrupt*/ | 439 | /* Prepare for async operations */ |
375 | kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); | 440 | host->data = data; |
441 | host->len = len; | ||
442 | host->state = state_addr; | ||
443 | host->result = 0; | ||
444 | host->rw = (addrdir & 1); | ||
445 | host->polled = bus->polled; | ||
446 | |||
447 | /* Enable interrupt if not using polled mode and interrupt is | ||
448 | * available | ||
449 | */ | ||
450 | if (use_irq) { | ||
451 | /* Clear completion */ | ||
452 | INIT_COMPLETION(host->complete); | ||
453 | /* Ack stale interrupts */ | ||
454 | kw_write_reg(reg_isr, kw_read_reg(reg_isr)); | ||
455 | /* Arm timeout */ | ||
456 | host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; | ||
457 | add_timer(&host->timeout_timer); | ||
458 | /* Enable emission */ | ||
459 | kw_write_reg(reg_ier, KW_I2C_IRQ_MASK); | ||
460 | } | ||
461 | |||
462 | /* Start sending address */ | ||
376 | kw_write_reg(reg_control, KW_I2C_CTL_XADDR); | 463 | kw_write_reg(reg_control, KW_I2C_CTL_XADDR); |
377 | 464 | ||
378 | /* State machine, to turn into an interrupt handler in the future */ | 465 | /* Wait for completion */ |
379 | while(state != state_idle) { | 466 | if (use_irq) |
380 | u8 isr = kw_i2c_wait_interrupt(bus); | 467 | wait_for_completion(&host->complete); |
381 | state = kw_i2c_handle_interrupt(bus, state, addrdir & 1, &rc, | 468 | else { |
382 | &data, &len, isr); | 469 | while(host->state != state_idle) { |
470 | unsigned long flags; | ||
471 | |||
472 | u8 isr = kw_i2c_wait_interrupt(host); | ||
473 | spin_lock_irqsave(&host->lock, flags); | ||
474 | kw_i2c_handle_interrupt(host, isr); | ||
475 | spin_unlock_irqrestore(&host->lock, flags); | ||
476 | } | ||
383 | } | 477 | } |
384 | 478 | ||
385 | return rc; | 479 | /* Disable emission */ |
480 | kw_write_reg(reg_ier, 0); | ||
481 | |||
482 | return host->result; | ||
386 | } | 483 | } |
387 | 484 | ||
388 | static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) | 485 | 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) | |||
409 | return NULL; | 506 | return NULL; |
410 | } | 507 | } |
411 | init_MUTEX(&host->mutex); | 508 | init_MUTEX(&host->mutex); |
509 | init_completion(&host->complete); | ||
510 | spin_lock_init(&host->lock); | ||
511 | init_timer(&host->timeout_timer); | ||
512 | host->timeout_timer.function = kw_i2c_timeout; | ||
513 | host->timeout_timer.data = (unsigned long)host; | ||
514 | |||
412 | psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); | 515 | psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); |
413 | steps = psteps ? (*psteps) : 0x10; | 516 | steps = psteps ? (*psteps) : 0x10; |
414 | for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) | 517 | 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) | |||
427 | host->speed = KW_I2C_MODE_25KHZ; | 530 | host->speed = KW_I2C_MODE_25KHZ; |
428 | break; | 531 | break; |
429 | } | 532 | } |
533 | if (np->n_intrs > 0) | ||
534 | host->irq = np->intrs[0].line; | ||
535 | else | ||
536 | host->irq = NO_IRQ; | ||
430 | 537 | ||
431 | printk(KERN_INFO "KeyWest i2c @0x%08x %s\n", *addrp, np->full_name); | ||
432 | host->base = ioremap((*addrp), 0x1000); | 538 | host->base = ioremap((*addrp), 0x1000); |
539 | if (host->base == NULL) { | ||
540 | printk(KERN_ERR "low_i2c: Can't map registers for %s\n", | ||
541 | np->full_name); | ||
542 | kfree(host); | ||
543 | return NULL; | ||
544 | } | ||
545 | |||
546 | /* Make sure IRA is disabled */ | ||
547 | kw_write_reg(reg_ier, 0); | ||
548 | |||
549 | /* Request chip interrupt */ | ||
550 | if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host)) | ||
551 | host->irq = NO_IRQ; | ||
552 | |||
553 | printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n", | ||
554 | *addrp, host->irq, np->full_name); | ||
433 | 555 | ||
434 | return host; | 556 | return host; |
435 | } | 557 | } |
@@ -591,7 +713,7 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
591 | req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; | 713 | req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; |
592 | req->done = pmu_i2c_complete; | 714 | req->done = pmu_i2c_complete; |
593 | req->arg = ∁ | 715 | req->arg = ∁ |
594 | if (!read) { | 716 | if (!read && len) { |
595 | memcpy(hdr->data, data, len); | 717 | memcpy(hdr->data, data, len); |
596 | req->nbytes += len; | 718 | req->nbytes += len; |
597 | } | 719 | } |
@@ -637,7 +759,8 @@ static int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
637 | " bytes, expected %d !\n", rlen, len); | 759 | " bytes, expected %d !\n", rlen, len); |
638 | return -EIO; | 760 | return -EIO; |
639 | } | 761 | } |
640 | memcpy(data, &req->reply[1], len); | 762 | if (len) |
763 | memcpy(data, &req->reply[1], len); | ||
641 | return 0; | 764 | return 0; |
642 | } | 765 | } |
643 | } | 766 | } |
@@ -713,6 +836,10 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
713 | int read = addrdir & 1; | 836 | int read = addrdir & 1; |
714 | int rc = 0; | 837 | int rc = 0; |
715 | 838 | ||
839 | if ((read && len > SMU_I2C_READ_MAX) || | ||
840 | ((!read) && len > SMU_I2C_WRITE_MAX)) | ||
841 | return -EINVAL; | ||
842 | |||
716 | memset(cmd, 0, sizeof(struct smu_i2c_cmd)); | 843 | memset(cmd, 0, sizeof(struct smu_i2c_cmd)); |
717 | cmd->info.bus = bus->channel; | 844 | cmd->info.bus = bus->channel; |
718 | cmd->info.devaddr = addrdir; | 845 | cmd->info.devaddr = addrdir; |
@@ -740,7 +867,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
740 | default: | 867 | default: |
741 | return -EINVAL; | 868 | return -EINVAL; |
742 | } | 869 | } |
743 | if (!read) | 870 | if (!read && len) |
744 | memcpy(cmd->info.data, data, len); | 871 | memcpy(cmd->info.data, data, len); |
745 | 872 | ||
746 | init_completion(&comp); | 873 | init_completion(&comp); |
@@ -752,7 +879,7 @@ static int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, | |||
752 | wait_for_completion(&comp); | 879 | wait_for_completion(&comp); |
753 | rc = cmd->status; | 880 | rc = cmd->status; |
754 | 881 | ||
755 | if (read) | 882 | if (read && len) |
756 | memcpy(data, cmd->info.data, len); | 883 | memcpy(data, cmd->info.data, len); |
757 | return rc < 0 ? rc : 0; | 884 | return rc < 0 ? rc : 0; |
758 | } | 885 | } |
@@ -767,7 +894,7 @@ static void __init smu_i2c_probe(void) | |||
767 | if (!smu_present()) | 894 | if (!smu_present()) |
768 | return; | 895 | return; |
769 | 896 | ||
770 | controller = of_find_node_by_name(NULL, "smu_i2c_control"); | 897 | controller = of_find_node_by_name(NULL, "smu-i2c-control"); |
771 | if (controller == NULL) | 898 | if (controller == NULL) |
772 | controller = of_find_node_by_name(NULL, "smu"); | 899 | controller = of_find_node_by_name(NULL, "smu"); |
773 | if (controller == NULL) | 900 | if (controller == NULL) |
@@ -884,6 +1011,13 @@ int pmac_i2c_get_flags(struct pmac_i2c_bus *bus) | |||
884 | } | 1011 | } |
885 | EXPORT_SYMBOL_GPL(pmac_i2c_get_flags); | 1012 | EXPORT_SYMBOL_GPL(pmac_i2c_get_flags); |
886 | 1013 | ||
1014 | int pmac_i2c_get_channel(struct pmac_i2c_bus *bus) | ||
1015 | { | ||
1016 | return bus->channel; | ||
1017 | } | ||
1018 | EXPORT_SYMBOL_GPL(pmac_i2c_get_channel); | ||
1019 | |||
1020 | |||
887 | void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, | 1021 | void pmac_i2c_attach_adapter(struct pmac_i2c_bus *bus, |
888 | struct i2c_adapter *adapter) | 1022 | struct i2c_adapter *adapter) |
889 | { | 1023 | { |
@@ -906,6 +1040,17 @@ struct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus) | |||
906 | } | 1040 | } |
907 | EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter); | 1041 | EXPORT_SYMBOL_GPL(pmac_i2c_get_adapter); |
908 | 1042 | ||
1043 | struct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter) | ||
1044 | { | ||
1045 | struct pmac_i2c_bus *bus; | ||
1046 | |||
1047 | list_for_each_entry(bus, &pmac_i2c_busses, link) | ||
1048 | if (bus->adapter == adapter) | ||
1049 | return bus; | ||
1050 | return NULL; | ||
1051 | } | ||
1052 | EXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus); | ||
1053 | |||
909 | extern int pmac_i2c_match_adapter(struct device_node *dev, | 1054 | extern int pmac_i2c_match_adapter(struct device_node *dev, |
910 | struct i2c_adapter *adapter) | 1055 | struct i2c_adapter *adapter) |
911 | { | 1056 | { |
@@ -956,7 +1101,7 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) | |||
956 | int rc; | 1101 | int rc; |
957 | 1102 | ||
958 | down(&bus->sem); | 1103 | down(&bus->sem); |
959 | bus->polled = polled; | 1104 | bus->polled = polled || pmac_i2c_force_poll; |
960 | bus->opened = 1; | 1105 | bus->opened = 1; |
961 | bus->mode = pmac_i2c_mode_std; | 1106 | bus->mode = pmac_i2c_mode_std; |
962 | if (bus->open && (rc = bus->open(bus)) != 0) { | 1107 | if (bus->open && (rc = bus->open(bus)) != 0) { |
@@ -1034,14 +1179,43 @@ int __init pmac_i2c_init(void) | |||
1034 | kw_i2c_probe(); | 1179 | kw_i2c_probe(); |
1035 | 1180 | ||
1036 | #ifdef CONFIG_ADB_PMU | 1181 | #ifdef CONFIG_ADB_PMU |
1182 | /* Probe PMU i2c busses */ | ||
1037 | pmu_i2c_probe(); | 1183 | pmu_i2c_probe(); |
1038 | #endif | 1184 | #endif |
1039 | 1185 | ||
1040 | #ifdef CONFIG_PMAC_SMU | 1186 | #ifdef CONFIG_PMAC_SMU |
1187 | /* Probe SMU i2c busses */ | ||
1041 | smu_i2c_probe(); | 1188 | smu_i2c_probe(); |
1042 | #endif | 1189 | #endif |
1043 | |||
1044 | return 0; | 1190 | return 0; |
1045 | } | 1191 | } |
1046 | arch_initcall(pmac_i2c_init); | 1192 | arch_initcall(pmac_i2c_init); |
1047 | 1193 | ||
1194 | /* Since pmac_i2c_init can be called too early for the platform device | ||
1195 | * registration, we need to do it at a later time. In our case, subsys | ||
1196 | * happens to fit well, though I agree it's a bit of a hack... | ||
1197 | */ | ||
1198 | static int __init pmac_i2c_create_platform_devices(void) | ||
1199 | { | ||
1200 | struct pmac_i2c_bus *bus; | ||
1201 | int i = 0; | ||
1202 | |||
1203 | /* In the case where we are initialized from smp_init(), we must | ||
1204 | * not use the timer (and thus the irq). It's safe from now on | ||
1205 | * though | ||
1206 | */ | ||
1207 | pmac_i2c_force_poll = 0; | ||
1208 | |||
1209 | /* Create platform devices */ | ||
1210 | list_for_each_entry(bus, &pmac_i2c_busses, link) { | ||
1211 | bus->platform_dev = | ||
1212 | platform_device_alloc("i2c-powermac", i++); | ||
1213 | if (bus->platform_dev == NULL) | ||
1214 | return -ENOMEM; | ||
1215 | bus->platform_dev->dev.platform_data = bus; | ||
1216 | platform_device_add(bus->platform_dev); | ||
1217 | } | ||
1218 | |||
1219 | return 0; | ||
1220 | } | ||
1221 | subsys_initcall(pmac_i2c_create_platform_devices); | ||
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index dc5cdc1484e8..3b1a9d4fcbc6 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) | |||
650 | 650 | ||
651 | static int __init pmac_declare_of_platform_devices(void) | 651 | static int __init pmac_declare_of_platform_devices(void) |
652 | { | 652 | { |
653 | struct device_node *np, *npp; | 653 | struct device_node *np; |
654 | 654 | ||
655 | np = of_find_node_by_name(NULL, "valkyrie"); | 655 | np = of_find_node_by_name(NULL, "valkyrie"); |
656 | if (np) | 656 | if (np) |
@@ -658,22 +658,6 @@ static int __init pmac_declare_of_platform_devices(void) | |||
658 | np = of_find_node_by_name(NULL, "platinum"); | 658 | np = of_find_node_by_name(NULL, "platinum"); |
659 | if (np) | 659 | if (np) |
660 | of_platform_device_create(np, "platinum", NULL); | 660 | of_platform_device_create(np, "platinum", NULL); |
661 | npp = of_find_node_by_name(NULL, "uni-n"); | ||
662 | if (npp == NULL) | ||
663 | npp = of_find_node_by_name(NULL, "u3"); | ||
664 | if (npp == NULL) | ||
665 | npp = of_find_node_by_name(NULL, "u4"); | ||
666 | if (npp) { | ||
667 | for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { | ||
668 | if (strncmp(np->name, "i2c", 3) == 0) { | ||
669 | of_platform_device_create(np, "uni-n-i2c", | ||
670 | NULL); | ||
671 | of_node_put(np); | ||
672 | break; | ||
673 | } | ||
674 | } | ||
675 | of_node_put(npp); | ||
676 | } | ||
677 | np = of_find_node_by_type(NULL, "smu"); | 661 | np = of_find_node_by_type(NULL, "smu"); |
678 | if (np) { | 662 | if (np) { |
679 | of_platform_device_create(np, "smu", NULL); | 663 | of_platform_device_create(np, "smu", NULL); |