aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/pmac_low_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel/pmac_low_i2c.c')
-rw-r--r--arch/ppc64/kernel/pmac_low_i2c.c523
1 files changed, 0 insertions, 523 deletions
diff --git a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c
deleted file mode 100644
index f3f39e8e337a..000000000000
--- a/arch/ppc64/kernel/pmac_low_i2c.c
+++ /dev/null
@@ -1,523 +0,0 @@
1/*
2 * arch/ppc/platforms/pmac_low_i2c.c
3 *
4 * Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * This file contains some low-level i2c access routines that
12 * need to be used by various bits of the PowerMac platform code
13 * at times where the real asynchronous & interrupt driven driver
14 * cannot be used. The API borrows some semantics from the darwin
15 * driver in order to ease the implementation of the platform
16 * properties parser
17 */
18
19#undef DEBUG
20
21#include <linux/config.h>
22#include <linux/types.h>
23#include <linux/sched.h>
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/adb.h>
27#include <linux/pmu.h>
28#include <asm/keylargo.h>
29#include <asm/uninorth.h>
30#include <asm/io.h>
31#include <asm/prom.h>
32#include <asm/machdep.h>
33#include <asm/pmac_low_i2c.h>
34
35#define MAX_LOW_I2C_HOST 4
36
37#ifdef DEBUG
38#define DBG(x...) do {\
39 printk(KERN_DEBUG "KW:" x); \
40 } while(0)
41#else
42#define DBG(x...)
43#endif
44
45struct low_i2c_host;
46
47typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
48
49struct low_i2c_host
50{
51 struct device_node *np; /* OF device node */
52 struct semaphore mutex; /* Access mutex for use by i2c-keywest */
53 low_i2c_func_t func; /* Access function */
54 unsigned int is_open : 1; /* Poor man's access control */
55 int mode; /* Current mode */
56 int channel; /* Current channel */
57 int num_channels; /* Number of channels */
58 void __iomem *base; /* For keywest-i2c, base address */
59 int bsteps; /* And register stepping */
60 int speed; /* And speed */
61};
62
63static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST];
64
65/* No locking is necessary on allocation, we are running way before
66 * anything can race with us
67 */
68static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
69{
70 int i;
71
72 for (i = 0; i < MAX_LOW_I2C_HOST; i++)
73 if (low_i2c_hosts[i].np == np)
74 return &low_i2c_hosts[i];
75 return NULL;
76}
77
78/*
79 *
80 * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
81 *
82 */
83
84/*
85 * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
86 * should be moved somewhere in include/asm-ppc/
87 */
88/* Register indices */
89typedef enum {
90 reg_mode = 0,
91 reg_control,
92 reg_status,
93 reg_isr,
94 reg_ier,
95 reg_addr,
96 reg_subaddr,
97 reg_data
98} reg_t;
99
100
101/* Mode register */
102#define KW_I2C_MODE_100KHZ 0x00
103#define KW_I2C_MODE_50KHZ 0x01
104#define KW_I2C_MODE_25KHZ 0x02
105#define KW_I2C_MODE_DUMB 0x00
106#define KW_I2C_MODE_STANDARD 0x04
107#define KW_I2C_MODE_STANDARDSUB 0x08
108#define KW_I2C_MODE_COMBINED 0x0C
109#define KW_I2C_MODE_MODE_MASK 0x0C
110#define KW_I2C_MODE_CHAN_MASK 0xF0
111
112/* Control register */
113#define KW_I2C_CTL_AAK 0x01
114#define KW_I2C_CTL_XADDR 0x02
115#define KW_I2C_CTL_STOP 0x04
116#define KW_I2C_CTL_START 0x08
117
118/* Status register */
119#define KW_I2C_STAT_BUSY 0x01
120#define KW_I2C_STAT_LAST_AAK 0x02
121#define KW_I2C_STAT_LAST_RW 0x04
122#define KW_I2C_STAT_SDA 0x08
123#define KW_I2C_STAT_SCL 0x10
124
125/* IER & ISR registers */
126#define KW_I2C_IRQ_DATA 0x01
127#define KW_I2C_IRQ_ADDR 0x02
128#define KW_I2C_IRQ_STOP 0x04
129#define KW_I2C_IRQ_START 0x08
130#define KW_I2C_IRQ_MASK 0x0F
131
132/* State machine states */
133enum {
134 state_idle,
135 state_addr,
136 state_read,
137 state_write,
138 state_stop,
139 state_dead
140};
141
142#define WRONG_STATE(name) do {\
143 printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
144 name, __kw_state_names[state], isr); \
145 } while(0)
146
147static const char *__kw_state_names[] = {
148 "state_idle",
149 "state_addr",
150 "state_read",
151 "state_write",
152 "state_stop",
153 "state_dead"
154};
155
156static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
157{
158 return readb(host->base + (((unsigned int)reg) << host->bsteps));
159}
160
161static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
162{
163 writeb(val, host->base + (((unsigned)reg) << host->bsteps));
164 (void)__kw_read_reg(host, reg_subaddr);
165}
166
167#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val)
168#define kw_read_reg(reg) __kw_read_reg(host, reg)
169
170
171/* Don't schedule, the g5 fan controller is too
172 * timing sensitive
173 */
174static u8 kw_wait_interrupt(struct low_i2c_host* host)
175{
176 int i, j;
177 u8 isr;
178
179 for (i = 0; i < 100000; i++) {
180 isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
181 if (isr != 0)
182 return isr;
183
184 /* This code is used with the timebase frozen, we cannot rely
185 * on udelay ! For now, just use a bogus loop
186 */
187 for (j = 1; j < 10000; j++)
188 mb();
189 }
190 return isr;
191}
192
193static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
194{
195 u8 ack;
196
197 DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr);
198
199 if (isr == 0) {
200 if (state != state_stop) {
201 DBG("KW: Timeout !\n");
202 *rc = -EIO;
203 goto stop;
204 }
205 if (state == state_stop) {
206 ack = kw_read_reg(reg_status);
207 if (!(ack & KW_I2C_STAT_BUSY)) {
208 state = state_idle;
209 kw_write_reg(reg_ier, 0x00);
210 }
211 }
212 return state;
213 }
214
215 if (isr & KW_I2C_IRQ_ADDR) {
216 ack = kw_read_reg(reg_status);
217 if (state != state_addr) {
218 kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
219 WRONG_STATE("KW_I2C_IRQ_ADDR");
220 *rc = -EIO;
221 goto stop;
222 }
223 if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
224 *rc = -ENODEV;
225 DBG("KW: NAK on address\n");
226 return state_stop;
227 } else {
228 if (rw) {
229 state = state_read;
230 if (*len > 1)
231 kw_write_reg(reg_control, KW_I2C_CTL_AAK);
232 } else {
233 state = state_write;
234 kw_write_reg(reg_data, **data);
235 (*data)++; (*len)--;
236 }
237 }
238 kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
239 }
240
241 if (isr & KW_I2C_IRQ_DATA) {
242 if (state == state_read) {
243 **data = kw_read_reg(reg_data);
244 (*data)++; (*len)--;
245 kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
246 if ((*len) == 0)
247 state = state_stop;
248 else if ((*len) == 1)
249 kw_write_reg(reg_control, 0);
250 } else if (state == state_write) {
251 ack = kw_read_reg(reg_status);
252 if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
253 DBG("KW: nack on data write\n");
254 *rc = -EIO;
255 goto stop;
256 } else if (*len) {
257 kw_write_reg(reg_data, **data);
258 (*data)++; (*len)--;
259 } else {
260 kw_write_reg(reg_control, KW_I2C_CTL_STOP);
261 state = state_stop;
262 *rc = 0;
263 }
264 kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
265 } else {
266 kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
267 WRONG_STATE("KW_I2C_IRQ_DATA");
268 if (state != state_stop) {
269 *rc = -EIO;
270 goto stop;
271 }
272 }
273 }
274
275 if (isr & KW_I2C_IRQ_STOP) {
276 kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
277 if (state != state_stop) {
278 WRONG_STATE("KW_I2C_IRQ_STOP");
279 *rc = -EIO;
280 }
281 return state_idle;
282 }
283
284 if (isr & KW_I2C_IRQ_START)
285 kw_write_reg(reg_isr, KW_I2C_IRQ_START);
286
287 return state;
288
289 stop:
290 kw_write_reg(reg_control, KW_I2C_CTL_STOP);
291 return state_stop;
292}
293
294static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
295{
296 u8 mode_reg = host->speed;
297 int state = state_addr;
298 int rc = 0;
299
300 /* Setup mode & subaddress if any */
301 switch(host->mode) {
302 case pmac_low_i2c_mode_dumb:
303 printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
304 return -EINVAL;
305 case pmac_low_i2c_mode_std:
306 mode_reg |= KW_I2C_MODE_STANDARD;
307 break;
308 case pmac_low_i2c_mode_stdsub:
309 mode_reg |= KW_I2C_MODE_STANDARDSUB;
310 break;
311 case pmac_low_i2c_mode_combined:
312 mode_reg |= KW_I2C_MODE_COMBINED;
313 break;
314 }
315
316 /* Setup channel & clear pending irqs */
317 kw_write_reg(reg_isr, kw_read_reg(reg_isr));
318 kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
319 kw_write_reg(reg_status, 0);
320
321 /* Set up address and r/w bit */
322 kw_write_reg(reg_addr, addr);
323
324 /* Set up the sub address */
325 if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB
326 || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
327 kw_write_reg(reg_subaddr, subaddr);
328
329 /* Start sending address & disable interrupt*/
330 kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
331 kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
332
333 /* State machine, to turn into an interrupt handler */
334 while(state != state_idle) {
335 u8 isr = kw_wait_interrupt(host);
336 state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
337 }
338
339 return rc;
340}
341
342static void keywest_low_i2c_add(struct device_node *np)
343{
344 struct low_i2c_host *host = find_low_i2c_host(NULL);
345 u32 *psteps, *prate, steps, aoffset = 0;
346 struct device_node *parent;
347
348 if (host == NULL) {
349 printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
350 np->full_name);
351 return;
352 }
353 memset(host, 0, sizeof(*host));
354
355 init_MUTEX(&host->mutex);
356 host->np = of_node_get(np);
357 psteps = (u32 *)get_property(np, "AAPL,address-step", NULL);
358 steps = psteps ? (*psteps) : 0x10;
359 for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
360 steps >>= 1;
361 parent = of_get_parent(np);
362 host->num_channels = 1;
363 if (parent && parent->name[0] == 'u') {
364 host->num_channels = 2;
365 aoffset = 3;
366 }
367 /* Select interface rate */
368 host->speed = KW_I2C_MODE_100KHZ;
369 prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL);
370 if (prate) switch(*prate) {
371 case 100:
372 host->speed = KW_I2C_MODE_100KHZ;
373 break;
374 case 50:
375 host->speed = KW_I2C_MODE_50KHZ;
376 break;
377 case 25:
378 host->speed = KW_I2C_MODE_25KHZ;
379 break;
380 }
381
382 host->mode = pmac_low_i2c_mode_std;
383 host->base = ioremap(np->addrs[0].address + aoffset,
384 np->addrs[0].size);
385 host->func = keywest_low_i2c_func;
386}
387
388/*
389 *
390 * PMU implementation
391 *
392 */
393
394
395#ifdef CONFIG_ADB_PMU
396
397static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
398{
399 // TODO
400 return -ENODEV;
401}
402
403static void pmu_low_i2c_add(struct device_node *np)
404{
405 struct low_i2c_host *host = find_low_i2c_host(NULL);
406
407 if (host == NULL) {
408 printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
409 np->full_name);
410 return;
411 }
412 memset(host, 0, sizeof(*host));
413
414 init_MUTEX(&host->mutex);
415 host->np = of_node_get(np);
416 host->num_channels = 3;
417 host->mode = pmac_low_i2c_mode_std;
418 host->func = pmu_low_i2c_func;
419}
420
421#endif /* CONFIG_ADB_PMU */
422
423void __init pmac_init_low_i2c(void)
424{
425 struct device_node *np;
426
427 /* Probe keywest-i2c busses */
428 np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
429 while(np) {
430 keywest_low_i2c_add(np);
431 np = of_find_compatible_node(np, "i2c", "keywest-i2c");
432 }
433
434#ifdef CONFIG_ADB_PMU
435 /* Probe PMU busses */
436 np = of_find_node_by_name(NULL, "via-pmu");
437 if (np)
438 pmu_low_i2c_add(np);
439#endif /* CONFIG_ADB_PMU */
440
441 /* TODO: Add CUDA support as well */
442}
443
444int pmac_low_i2c_lock(struct device_node *np)
445{
446 struct low_i2c_host *host = find_low_i2c_host(np);
447
448 if (!host)
449 return -ENODEV;
450 down(&host->mutex);
451 return 0;
452}
453EXPORT_SYMBOL(pmac_low_i2c_lock);
454
455int pmac_low_i2c_unlock(struct device_node *np)
456{
457 struct low_i2c_host *host = find_low_i2c_host(np);
458
459 if (!host)
460 return -ENODEV;
461 up(&host->mutex);
462 return 0;
463}
464EXPORT_SYMBOL(pmac_low_i2c_unlock);
465
466
467int pmac_low_i2c_open(struct device_node *np, int channel)
468{
469 struct low_i2c_host *host = find_low_i2c_host(np);
470
471 if (!host)
472 return -ENODEV;
473
474 if (channel >= host->num_channels)
475 return -EINVAL;
476
477 down(&host->mutex);
478 host->is_open = 1;
479 host->channel = channel;
480
481 return 0;
482}
483EXPORT_SYMBOL(pmac_low_i2c_open);
484
485int pmac_low_i2c_close(struct device_node *np)
486{
487 struct low_i2c_host *host = find_low_i2c_host(np);
488
489 if (!host)
490 return -ENODEV;
491
492 host->is_open = 0;
493 up(&host->mutex);
494
495 return 0;
496}
497EXPORT_SYMBOL(pmac_low_i2c_close);
498
499int pmac_low_i2c_setmode(struct device_node *np, int mode)
500{
501 struct low_i2c_host *host = find_low_i2c_host(np);
502
503 if (!host)
504 return -ENODEV;
505 WARN_ON(!host->is_open);
506 host->mode = mode;
507
508 return 0;
509}
510EXPORT_SYMBOL(pmac_low_i2c_setmode);
511
512int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
513{
514 struct low_i2c_host *host = find_low_i2c_host(np);
515
516 if (!host)
517 return -ENODEV;
518 WARN_ON(!host->is_open);
519
520 return host->func(host, addrdir, subaddr, data, len);
521}
522EXPORT_SYMBOL(pmac_low_i2c_xfer);
523