diff options
Diffstat (limited to 'drivers/sbus')
-rw-r--r-- | drivers/sbus/char/bbc_envctrl.c | 121 | ||||
-rw-r--r-- | drivers/sbus/char/bbc_i2c.c | 267 | ||||
-rw-r--r-- | drivers/sbus/char/bbc_i2c.h | 75 |
3 files changed, 214 insertions, 249 deletions
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 0bde26989a23..abe4d50de21d 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c | |||
@@ -1,15 +1,15 @@ | |||
1 | /* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ | 1 | /* bbc_envctrl.c: UltraSPARC-III environment control driver. |
2 | * bbc_envctrl.c: UltraSPARC-III environment control driver. | ||
3 | * | 2 | * |
4 | * Copyright (C) 2001 David S. Miller (davem@redhat.com) | 3 | * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) |
5 | */ | 4 | */ |
6 | 5 | ||
7 | #include <linux/kthread.h> | 6 | #include <linux/kthread.h> |
8 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
9 | #include <linux/kmod.h> | 8 | #include <linux/kmod.h> |
10 | #include <linux/reboot.h> | 9 | #include <linux/reboot.h> |
10 | #include <linux/of.h> | ||
11 | #include <linux/of_device.h> | ||
11 | #include <asm/oplib.h> | 12 | #include <asm/oplib.h> |
12 | #include <asm/ebus.h> | ||
13 | 13 | ||
14 | #include "bbc_i2c.h" | 14 | #include "bbc_i2c.h" |
15 | #include "max1617.h" | 15 | #include "max1617.h" |
@@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = { | |||
75 | { 65, 55, 40, 5, -5, -10 }, | 75 | { 65, 55, 40, 5, -5, -10 }, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; | 78 | static LIST_HEAD(all_temps); |
79 | 79 | static LIST_HEAD(all_fans); | |
80 | struct bbc_cpu_temperature { | ||
81 | struct bbc_cpu_temperature *next; | ||
82 | |||
83 | struct bbc_i2c_client *client; | ||
84 | int index; | ||
85 | |||
86 | /* Current readings, and history. */ | ||
87 | s8 curr_cpu_temp; | ||
88 | s8 curr_amb_temp; | ||
89 | s8 prev_cpu_temp; | ||
90 | s8 prev_amb_temp; | ||
91 | s8 avg_cpu_temp; | ||
92 | s8 avg_amb_temp; | ||
93 | |||
94 | int sample_tick; | ||
95 | |||
96 | enum fan_action fan_todo[2]; | ||
97 | #define FAN_AMBIENT 0 | ||
98 | #define FAN_CPU 1 | ||
99 | }; | ||
100 | |||
101 | struct bbc_cpu_temperature *all_bbc_temps; | ||
102 | |||
103 | struct bbc_fan_control { | ||
104 | struct bbc_fan_control *next; | ||
105 | |||
106 | struct bbc_i2c_client *client; | ||
107 | int index; | ||
108 | |||
109 | int psupply_fan_on; | ||
110 | int cpu_fan_speed; | ||
111 | int system_fan_speed; | ||
112 | }; | ||
113 | |||
114 | struct bbc_fan_control *all_bbc_fans; | ||
115 | 80 | ||
116 | #define CPU_FAN_REG 0xf0 | 81 | #define CPU_FAN_REG 0xf0 |
117 | #define SYS_FAN_REG 0xf2 | 82 | #define SYS_FAN_REG 0xf2 |
@@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan) | |||
330 | * recommend we do, and perform that action on all the | 295 | * recommend we do, and perform that action on all the |
331 | * fans. | 296 | * fans. |
332 | */ | 297 | */ |
333 | for (tp = all_bbc_temps; tp; tp = tp->next) { | 298 | list_for_each_entry(tp, &all_temps, glob_list) { |
334 | if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { | 299 | if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { |
335 | decision = FAN_FULLBLAST; | 300 | decision = FAN_FULLBLAST; |
336 | break; | 301 | break; |
@@ -439,7 +404,7 @@ static void fans_full_blast(void) | |||
439 | /* Since we will not be monitoring things anymore, put | 404 | /* Since we will not be monitoring things anymore, put |
440 | * the fans on full blast. | 405 | * the fans on full blast. |
441 | */ | 406 | */ |
442 | for (fp = all_bbc_fans; fp; fp = fp->next) { | 407 | list_for_each_entry(fp, &all_fans, glob_list) { |
443 | fp->cpu_fan_speed = FAN_SPEED_MAX; | 408 | fp->cpu_fan_speed = FAN_SPEED_MAX; |
444 | fp->system_fan_speed = FAN_SPEED_MAX; | 409 | fp->system_fan_speed = FAN_SPEED_MAX; |
445 | fp->psupply_fan_on = 1; | 410 | fp->psupply_fan_on = 1; |
@@ -463,11 +428,11 @@ static int kenvctrld(void *__unused) | |||
463 | if (kthread_should_stop()) | 428 | if (kthread_should_stop()) |
464 | break; | 429 | break; |
465 | 430 | ||
466 | for (tp = all_bbc_temps; tp; tp = tp->next) { | 431 | list_for_each_entry(tp, &all_temps, glob_list) { |
467 | get_current_temps(tp); | 432 | get_current_temps(tp); |
468 | analyze_temps(tp, &last_warning_jiffies); | 433 | analyze_temps(tp, &last_warning_jiffies); |
469 | } | 434 | } |
470 | for (fp = all_bbc_fans; fp; fp = fp->next) | 435 | list_for_each_entry(fp, &all_fans, glob_list) |
471 | maybe_new_fan_speeds(fp); | 436 | maybe_new_fan_speeds(fp); |
472 | } | 437 | } |
473 | printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); | 438 | printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); |
@@ -477,7 +442,8 @@ static int kenvctrld(void *__unused) | |||
477 | return 0; | 442 | return 0; |
478 | } | 443 | } |
479 | 444 | ||
480 | static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) | 445 | static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, |
446 | int temp_idx) | ||
481 | { | 447 | { |
482 | struct bbc_cpu_temperature *tp; | 448 | struct bbc_cpu_temperature *tp; |
483 | 449 | ||
@@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) | |||
485 | if (!tp) | 451 | if (!tp) |
486 | return; | 452 | return; |
487 | 453 | ||
488 | tp->client = bbc_i2c_attach(echild); | 454 | tp->client = bbc_i2c_attach(op); |
489 | if (!tp->client) { | 455 | if (!tp->client) { |
490 | kfree(tp); | 456 | kfree(tp); |
491 | return; | 457 | return; |
492 | } | 458 | } |
493 | 459 | ||
460 | |||
494 | tp->index = temp_idx; | 461 | tp->index = temp_idx; |
495 | { | 462 | |
496 | struct bbc_cpu_temperature **tpp = &all_bbc_temps; | 463 | list_add(&tp->glob_list, &all_temps); |
497 | while (*tpp) | 464 | list_add(&tp->bp_list, &bp->temps); |
498 | tpp = &((*tpp)->next); | ||
499 | tp->next = NULL; | ||
500 | *tpp = tp; | ||
501 | } | ||
502 | 465 | ||
503 | /* Tell it to convert once every 5 seconds, clear all cfg | 466 | /* Tell it to convert once every 5 seconds, clear all cfg |
504 | * bits. | 467 | * bits. |
@@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) | |||
524 | tp->fan_todo[FAN_CPU] = FAN_SAME; | 487 | tp->fan_todo[FAN_CPU] = FAN_SAME; |
525 | } | 488 | } |
526 | 489 | ||
527 | static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) | 490 | static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, |
491 | int fan_idx) | ||
528 | { | 492 | { |
529 | struct bbc_fan_control *fp; | 493 | struct bbc_fan_control *fp; |
530 | 494 | ||
@@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) | |||
532 | if (!fp) | 496 | if (!fp) |
533 | return; | 497 | return; |
534 | 498 | ||
535 | fp->client = bbc_i2c_attach(echild); | 499 | fp->client = bbc_i2c_attach(op); |
536 | if (!fp->client) { | 500 | if (!fp->client) { |
537 | kfree(fp); | 501 | kfree(fp); |
538 | return; | 502 | return; |
@@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) | |||
540 | 504 | ||
541 | fp->index = fan_idx; | 505 | fp->index = fan_idx; |
542 | 506 | ||
543 | { | 507 | list_add(&fp->glob_list, &all_fans); |
544 | struct bbc_fan_control **fpp = &all_bbc_fans; | 508 | list_add(&fp->bp_list, &bp->fans); |
545 | while (*fpp) | ||
546 | fpp = &((*fpp)->next); | ||
547 | fp->next = NULL; | ||
548 | *fpp = fp; | ||
549 | } | ||
550 | 509 | ||
551 | /* The i2c device controlling the fans is write-only. | 510 | /* The i2c device controlling the fans is write-only. |
552 | * So the only way to keep track of the current power | 511 | * So the only way to keep track of the current power |
@@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) | |||
563 | set_fan_speeds(fp); | 522 | set_fan_speeds(fp); |
564 | } | 523 | } |
565 | 524 | ||
566 | int bbc_envctrl_init(void) | 525 | int bbc_envctrl_init(struct bbc_i2c_bus *bp) |
567 | { | 526 | { |
568 | struct linux_ebus_child *echild; | 527 | struct of_device *op; |
569 | int temp_index = 0; | 528 | int temp_index = 0; |
570 | int fan_index = 0; | 529 | int fan_index = 0; |
571 | int devidx = 0; | 530 | int devidx = 0; |
572 | 531 | ||
573 | while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { | 532 | while ((op = bbc_i2c_getdev(devidx++)) != NULL) { |
574 | if (!strcmp(echild->prom_node->name, "temperature")) | 533 | if (!strcmp(op->node->name, "temperature")) |
575 | attach_one_temp(echild, temp_index++); | 534 | attach_one_temp(bp, op, temp_index++); |
576 | if (!strcmp(echild->prom_node->name, "fan-control")) | 535 | if (!strcmp(op->node->name, "fan-control")) |
577 | attach_one_fan(echild, fan_index++); | 536 | attach_one_fan(bp, op, fan_index++); |
578 | } | 537 | } |
579 | if (temp_index != 0 && fan_index != 0) { | 538 | if (temp_index != 0 && fan_index != 0) { |
580 | kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); | 539 | kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); |
@@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp) | |||
597 | kfree(fp); | 556 | kfree(fp); |
598 | } | 557 | } |
599 | 558 | ||
600 | void bbc_envctrl_cleanup(void) | 559 | void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) |
601 | { | 560 | { |
602 | struct bbc_cpu_temperature *tp; | 561 | struct bbc_cpu_temperature *tp, *tpos; |
603 | struct bbc_fan_control *fp; | 562 | struct bbc_fan_control *fp, *fpos; |
604 | 563 | ||
605 | kthread_stop(kenvctrld_task); | 564 | kthread_stop(kenvctrld_task); |
606 | 565 | ||
607 | tp = all_bbc_temps; | 566 | list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) { |
608 | while (tp != NULL) { | 567 | list_del(&tp->bp_list); |
609 | struct bbc_cpu_temperature *next = tp->next; | 568 | list_del(&tp->glob_list); |
610 | destroy_one_temp(tp); | 569 | destroy_one_temp(tp); |
611 | tp = next; | ||
612 | } | 570 | } |
613 | all_bbc_temps = NULL; | ||
614 | 571 | ||
615 | fp = all_bbc_fans; | 572 | list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) { |
616 | while (fp != NULL) { | 573 | list_del(&fp->bp_list); |
617 | struct bbc_fan_control *next = fp->next; | 574 | list_del(&fp->glob_list); |
618 | destroy_one_fan(fp); | 575 | destroy_one_fan(fp); |
619 | fp = next; | ||
620 | } | 576 | } |
621 | all_bbc_fans = NULL; | ||
622 | } | 577 | } |
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index ac8ef2ce07fb..af7f4af6c5fb 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ | 1 | /* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III |
2 | * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III | ||
3 | * platforms. | 2 | * platforms. |
4 | * | 3 | * |
5 | * Copyright (C) 2001 David S. Miller (davem@redhat.com) | 4 | * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) |
6 | */ | 5 | */ |
7 | 6 | ||
8 | #include <linux/module.h> | 7 | #include <linux/module.h> |
@@ -14,9 +13,8 @@ | |||
14 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
17 | #include <asm/oplib.h> | 16 | #include <linux/of.h> |
18 | #include <asm/ebus.h> | 17 | #include <linux/of_device.h> |
19 | #include <asm/spitfire.h> | ||
20 | #include <asm/bbc.h> | 18 | #include <asm/bbc.h> |
21 | #include <asm/io.h> | 19 | #include <asm/io.h> |
22 | 20 | ||
@@ -53,54 +51,12 @@ | |||
53 | * The second controller also connects to the smartcard reader, if present. | 51 | * The second controller also connects to the smartcard reader, if present. |
54 | */ | 52 | */ |
55 | 53 | ||
56 | #define NUM_CHILDREN 8 | 54 | static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val) |
57 | struct bbc_i2c_bus { | ||
58 | struct bbc_i2c_bus *next; | ||
59 | int index; | ||
60 | spinlock_t lock; | ||
61 | void __iomem *i2c_bussel_reg; | ||
62 | void __iomem *i2c_control_regs; | ||
63 | unsigned char own, clock; | ||
64 | |||
65 | wait_queue_head_t wq; | ||
66 | volatile int waiting; | ||
67 | |||
68 | struct linux_ebus_device *bus_edev; | ||
69 | struct { | ||
70 | struct linux_ebus_child *device; | ||
71 | int client_claimed; | ||
72 | } devs[NUM_CHILDREN]; | ||
73 | }; | ||
74 | |||
75 | static struct bbc_i2c_bus *all_bbc_i2c; | ||
76 | |||
77 | struct bbc_i2c_client { | ||
78 | struct bbc_i2c_bus *bp; | ||
79 | struct linux_ebus_child *echild; | ||
80 | int bus; | ||
81 | int address; | ||
82 | }; | ||
83 | |||
84 | static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) | ||
85 | { | 55 | { |
86 | int i; | 56 | int i; |
87 | 57 | ||
88 | for (i = 0; i < NUM_CHILDREN; i++) { | 58 | for (i = 0; i < NUM_CHILDREN; i++) { |
89 | if (bp->devs[i].device == echild) { | 59 | if (bp->devs[i].device == op) { |
90 | if (bp->devs[i].client_claimed) | ||
91 | return 0; | ||
92 | return 1; | ||
93 | } | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | for (i = 0; i < NUM_CHILDREN; i++) { | ||
103 | if (bp->devs[i].device == echild) { | ||
104 | bp->devs[i].client_claimed = val; | 60 | bp->devs[i].client_claimed = val; |
105 | return; | 61 | return; |
106 | } | 62 | } |
@@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child | |||
110 | #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) | 66 | #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) |
111 | #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) | 67 | #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) |
112 | 68 | ||
113 | static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) | 69 | struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) |
114 | { | 70 | { |
115 | struct bbc_i2c_bus *bp = all_bbc_i2c; | 71 | struct of_device *op = NULL; |
72 | int curidx = 0, i; | ||
116 | 73 | ||
117 | while (bp != NULL) { | 74 | for (i = 0; i < NUM_CHILDREN; i++) { |
118 | if (find_device(bp, echild) != 0) | 75 | if (!(op = bp->devs[i].device)) |
119 | break; | 76 | break; |
120 | bp = bp->next; | 77 | if (curidx == index) |
78 | goto out; | ||
79 | op = NULL; | ||
80 | curidx++; | ||
121 | } | 81 | } |
122 | 82 | ||
123 | return bp; | ||
124 | } | ||
125 | |||
126 | struct linux_ebus_child *bbc_i2c_getdev(int index) | ||
127 | { | ||
128 | struct bbc_i2c_bus *bp = all_bbc_i2c; | ||
129 | struct linux_ebus_child *echild = NULL; | ||
130 | int curidx = 0; | ||
131 | |||
132 | while (bp != NULL) { | ||
133 | struct bbc_i2c_bus *next = bp->next; | ||
134 | int i; | ||
135 | |||
136 | for (i = 0; i < NUM_CHILDREN; i++) { | ||
137 | if (!(echild = bp->devs[i].device)) | ||
138 | break; | ||
139 | if (curidx == index) | ||
140 | goto out; | ||
141 | echild = NULL; | ||
142 | curidx++; | ||
143 | } | ||
144 | bp = next; | ||
145 | } | ||
146 | out: | 83 | out: |
147 | if (curidx == index) | 84 | if (curidx == index) |
148 | return echild; | 85 | return op; |
149 | return NULL; | 86 | return NULL; |
150 | } | 87 | } |
151 | 88 | ||
152 | struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) | 89 | struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op) |
153 | { | 90 | { |
154 | struct bbc_i2c_bus *bp = find_bus_for_device(echild); | ||
155 | struct bbc_i2c_client *client; | 91 | struct bbc_i2c_client *client; |
92 | const u32 *reg; | ||
156 | 93 | ||
157 | if (!bp) | ||
158 | return NULL; | ||
159 | client = kzalloc(sizeof(*client), GFP_KERNEL); | 94 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
160 | if (!client) | 95 | if (!client) |
161 | return NULL; | 96 | return NULL; |
162 | client->bp = bp; | 97 | client->bp = bp; |
163 | client->echild = echild; | 98 | client->op = op; |
164 | client->bus = echild->resource[0].start; | 99 | |
165 | client->address = echild->resource[1].start; | 100 | reg = of_get_property(op->node, "reg", NULL); |
101 | if (!reg) { | ||
102 | kfree(client); | ||
103 | return NULL; | ||
104 | } | ||
166 | 105 | ||
167 | claim_device(bp, echild); | 106 | client->bus = reg[0]; |
107 | client->address = reg[1]; | ||
108 | |||
109 | claim_device(bp, op); | ||
168 | 110 | ||
169 | return client; | 111 | return client; |
170 | } | 112 | } |
@@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) | |||
172 | void bbc_i2c_detach(struct bbc_i2c_client *client) | 114 | void bbc_i2c_detach(struct bbc_i2c_client *client) |
173 | { | 115 | { |
174 | struct bbc_i2c_bus *bp = client->bp; | 116 | struct bbc_i2c_bus *bp = client->bp; |
175 | struct linux_ebus_child *echild = client->echild; | 117 | struct of_device *op = client->op; |
176 | 118 | ||
177 | release_device(bp, echild); | 119 | release_device(bp, op); |
178 | kfree(client); | 120 | kfree(client); |
179 | } | 121 | } |
180 | 122 | ||
@@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp) | |||
355 | writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); | 297 | writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); |
356 | } | 298 | } |
357 | 299 | ||
358 | static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) | 300 | static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index) |
359 | { | 301 | { |
360 | struct bbc_i2c_bus *bp; | 302 | struct bbc_i2c_bus *bp; |
361 | struct linux_ebus_child *echild; | 303 | struct device_node *dp; |
362 | int entry; | 304 | int entry; |
363 | 305 | ||
364 | bp = kzalloc(sizeof(*bp), GFP_KERNEL); | 306 | bp = kzalloc(sizeof(*bp), GFP_KERNEL); |
365 | if (!bp) | 307 | if (!bp) |
366 | return -ENOMEM; | 308 | return NULL; |
367 | 309 | ||
368 | bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); | 310 | bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); |
369 | if (!bp->i2c_control_regs) | 311 | if (!bp->i2c_control_regs) |
370 | goto fail; | 312 | goto fail; |
371 | 313 | ||
372 | if (edev->num_addrs == 2) { | 314 | bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); |
373 | bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); | 315 | if (!bp->i2c_bussel_reg) |
374 | if (!bp->i2c_bussel_reg) | 316 | goto fail; |
375 | goto fail; | ||
376 | } | ||
377 | 317 | ||
378 | bp->waiting = 0; | 318 | bp->waiting = 0; |
379 | init_waitqueue_head(&bp->wq); | 319 | init_waitqueue_head(&bp->wq); |
380 | if (request_irq(edev->irqs[0], bbc_i2c_interrupt, | 320 | if (request_irq(op->irqs[0], bbc_i2c_interrupt, |
381 | IRQF_SHARED, "bbc_i2c", bp)) | 321 | IRQF_SHARED, "bbc_i2c", bp)) |
382 | goto fail; | 322 | goto fail; |
383 | 323 | ||
384 | bp->index = index; | 324 | bp->index = index; |
385 | bp->bus_edev = edev; | 325 | bp->op = op; |
386 | 326 | ||
387 | spin_lock_init(&bp->lock); | 327 | spin_lock_init(&bp->lock); |
388 | bp->next = all_bbc_i2c; | ||
389 | all_bbc_i2c = bp; | ||
390 | 328 | ||
391 | entry = 0; | 329 | entry = 0; |
392 | for (echild = edev->children; | 330 | for (dp = op->node->child; |
393 | echild && entry < 8; | 331 | dp && entry < 8; |
394 | echild = echild->next, entry++) { | 332 | dp = dp->sibling, entry++) { |
395 | bp->devs[entry].device = echild; | 333 | struct of_device *child_op; |
334 | |||
335 | child_op = of_find_device_by_node(dp); | ||
336 | bp->devs[entry].device = child_op; | ||
396 | bp->devs[entry].client_claimed = 0; | 337 | bp->devs[entry].client_claimed = 0; |
397 | } | 338 | } |
398 | 339 | ||
@@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) | |||
406 | 347 | ||
407 | reset_one_i2c(bp); | 348 | reset_one_i2c(bp); |
408 | 349 | ||
409 | return 0; | 350 | return bp; |
410 | 351 | ||
411 | fail: | 352 | fail: |
412 | if (bp->i2c_bussel_reg) | 353 | if (bp->i2c_bussel_reg) |
413 | iounmap(bp->i2c_bussel_reg); | 354 | of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); |
414 | if (bp->i2c_control_regs) | 355 | if (bp->i2c_control_regs) |
415 | iounmap(bp->i2c_control_regs); | 356 | of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); |
416 | kfree(bp); | 357 | kfree(bp); |
417 | return -EINVAL; | 358 | return NULL; |
418 | } | ||
419 | |||
420 | static int __init bbc_present(void) | ||
421 | { | ||
422 | struct linux_ebus *ebus = NULL; | ||
423 | struct linux_ebus_device *edev = NULL; | ||
424 | |||
425 | for_each_ebus(ebus) { | ||
426 | for_each_ebusdev(edev, ebus) { | ||
427 | if (!strcmp(edev->prom_node->name, "bbc")) | ||
428 | return 1; | ||
429 | } | ||
430 | } | ||
431 | return 0; | ||
432 | } | 359 | } |
433 | 360 | ||
434 | extern int bbc_envctrl_init(void); | 361 | extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); |
435 | extern void bbc_envctrl_cleanup(void); | 362 | extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); |
436 | static void bbc_i2c_cleanup(void); | ||
437 | 363 | ||
438 | static int __init bbc_i2c_init(void) | 364 | static int __devinit bbc_i2c_probe(struct of_device *op, |
365 | const struct of_device_id *match) | ||
439 | { | 366 | { |
440 | struct linux_ebus *ebus = NULL; | 367 | struct bbc_i2c_bus *bp; |
441 | struct linux_ebus_device *edev = NULL; | ||
442 | int err, index = 0; | 368 | int err, index = 0; |
443 | 369 | ||
444 | if ((tlb_type != cheetah && tlb_type != cheetah_plus) || | 370 | bp = attach_one_i2c(op, index); |
445 | !bbc_present()) | 371 | if (!bp) |
446 | return -ENODEV; | 372 | return -EINVAL; |
447 | 373 | ||
448 | for_each_ebus(ebus) { | 374 | err = bbc_envctrl_init(bp); |
449 | for_each_ebusdev(edev, ebus) { | 375 | if (err) { |
450 | if (!strcmp(edev->prom_node->name, "i2c")) { | 376 | free_irq(op->irqs[0], bp); |
451 | if (!attach_one_i2c(edev, index)) | 377 | if (bp->i2c_bussel_reg) |
452 | index++; | 378 | of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); |
453 | } | 379 | if (bp->i2c_control_regs) |
454 | } | 380 | of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); |
381 | kfree(bp); | ||
382 | } else { | ||
383 | dev_set_drvdata(&op->dev, bp); | ||
455 | } | 384 | } |
456 | 385 | ||
457 | if (!index) | ||
458 | return -ENODEV; | ||
459 | |||
460 | err = bbc_envctrl_init(); | ||
461 | if (err) | ||
462 | bbc_i2c_cleanup(); | ||
463 | return err; | 386 | return err; |
464 | } | 387 | } |
465 | 388 | ||
466 | static void bbc_i2c_cleanup(void) | 389 | static int __devexit bbc_i2c_remove(struct of_device *op) |
467 | { | 390 | { |
468 | struct bbc_i2c_bus *bp = all_bbc_i2c; | 391 | struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); |
392 | |||
393 | bbc_envctrl_cleanup(bp); | ||
394 | |||
395 | free_irq(op->irqs[0], bp); | ||
469 | 396 | ||
470 | bbc_envctrl_cleanup(); | 397 | if (bp->i2c_bussel_reg) |
398 | of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); | ||
399 | if (bp->i2c_control_regs) | ||
400 | of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); | ||
471 | 401 | ||
472 | while (bp != NULL) { | 402 | kfree(bp); |
473 | struct bbc_i2c_bus *next = bp->next; | ||
474 | 403 | ||
475 | free_irq(bp->bus_edev->irqs[0], bp); | 404 | return 0; |
405 | } | ||
476 | 406 | ||
477 | if (bp->i2c_bussel_reg) | 407 | static struct of_device_id bbc_i2c_match[] = { |
478 | iounmap(bp->i2c_bussel_reg); | 408 | { |
479 | if (bp->i2c_control_regs) | 409 | .name = "i2c", |
480 | iounmap(bp->i2c_control_regs); | 410 | .compatible = "SUNW,bbc-i2c", |
411 | }, | ||
412 | {}, | ||
413 | }; | ||
414 | MODULE_DEVICE_TABLE(of, bbc_i2c_match); | ||
481 | 415 | ||
482 | kfree(bp); | 416 | static struct of_platform_driver bbc_i2c_driver = { |
417 | .name = "bbc_i2c", | ||
418 | .match_table = bbc_i2c_match, | ||
419 | .probe = bbc_i2c_probe, | ||
420 | .remove = __devexit_p(bbc_i2c_remove), | ||
421 | }; | ||
483 | 422 | ||
484 | bp = next; | 423 | static int __init bbc_i2c_init(void) |
485 | } | 424 | { |
486 | all_bbc_i2c = NULL; | 425 | return of_register_driver(&bbc_i2c_driver, &of_bus_type); |
426 | } | ||
427 | |||
428 | static void __exit bbc_i2c_exit(void) | ||
429 | { | ||
430 | of_unregister_driver(&bbc_i2c_driver); | ||
487 | } | 431 | } |
488 | 432 | ||
489 | module_init(bbc_i2c_init); | 433 | module_init(bbc_i2c_init); |
490 | module_exit(bbc_i2c_cleanup); | 434 | module_exit(bbc_i2c_exit); |
435 | |||
491 | MODULE_LICENSE("GPL"); | 436 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h index fb01bd17704b..83c4811b7b5e 100644 --- a/drivers/sbus/char/bbc_i2c.h +++ b/drivers/sbus/char/bbc_i2c.h | |||
@@ -1,14 +1,79 @@ | |||
1 | /* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ | ||
2 | #ifndef _BBC_I2C_H | 1 | #ifndef _BBC_I2C_H |
3 | #define _BBC_I2C_H | 2 | #define _BBC_I2C_H |
4 | 3 | ||
5 | #include <asm/ebus.h> | 4 | #include <linux/of.h> |
5 | #include <linux/of_device.h> | ||
6 | #include <linux/list.h> | ||
6 | 7 | ||
7 | struct bbc_i2c_client; | 8 | struct bbc_i2c_client { |
9 | struct bbc_i2c_bus *bp; | ||
10 | struct of_device *op; | ||
11 | int bus; | ||
12 | int address; | ||
13 | }; | ||
14 | |||
15 | enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; | ||
16 | |||
17 | struct bbc_cpu_temperature { | ||
18 | struct list_head bp_list; | ||
19 | struct list_head glob_list; | ||
20 | |||
21 | struct bbc_i2c_client *client; | ||
22 | int index; | ||
23 | |||
24 | /* Current readings, and history. */ | ||
25 | s8 curr_cpu_temp; | ||
26 | s8 curr_amb_temp; | ||
27 | s8 prev_cpu_temp; | ||
28 | s8 prev_amb_temp; | ||
29 | s8 avg_cpu_temp; | ||
30 | s8 avg_amb_temp; | ||
31 | |||
32 | int sample_tick; | ||
33 | |||
34 | enum fan_action fan_todo[2]; | ||
35 | #define FAN_AMBIENT 0 | ||
36 | #define FAN_CPU 1 | ||
37 | }; | ||
38 | |||
39 | struct bbc_fan_control { | ||
40 | struct list_head bp_list; | ||
41 | struct list_head glob_list; | ||
42 | |||
43 | struct bbc_i2c_client *client; | ||
44 | int index; | ||
45 | |||
46 | int psupply_fan_on; | ||
47 | int cpu_fan_speed; | ||
48 | int system_fan_speed; | ||
49 | }; | ||
50 | |||
51 | #define NUM_CHILDREN 8 | ||
52 | |||
53 | struct bbc_i2c_bus { | ||
54 | struct bbc_i2c_bus *next; | ||
55 | int index; | ||
56 | spinlock_t lock; | ||
57 | void __iomem *i2c_bussel_reg; | ||
58 | void __iomem *i2c_control_regs; | ||
59 | unsigned char own, clock; | ||
60 | |||
61 | wait_queue_head_t wq; | ||
62 | volatile int waiting; | ||
63 | |||
64 | struct list_head temps; | ||
65 | struct list_head fans; | ||
66 | |||
67 | struct of_device *op; | ||
68 | struct { | ||
69 | struct of_device *device; | ||
70 | int client_claimed; | ||
71 | } devs[NUM_CHILDREN]; | ||
72 | }; | ||
8 | 73 | ||
9 | /* Probing and attachment. */ | 74 | /* Probing and attachment. */ |
10 | extern struct linux_ebus_child *bbc_i2c_getdev(int); | 75 | extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int); |
11 | extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); | 76 | extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *); |
12 | extern void bbc_i2c_detach(struct bbc_i2c_client *); | 77 | extern void bbc_i2c_detach(struct bbc_i2c_client *); |
13 | 78 | ||
14 | /* Register read/write. NOTE: Blocking! */ | 79 | /* Register read/write. NOTE: Blocking! */ |