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