diff options
Diffstat (limited to 'arch/powerpc/platforms/44x/warp.c')
-rw-r--r-- | arch/powerpc/platforms/44x/warp.c | 293 |
1 files changed, 243 insertions, 50 deletions
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 39cf6150a72b..9565995cba7f 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c | |||
@@ -12,6 +12,9 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/of_platform.h> | 13 | #include <linux/of_platform.h> |
14 | #include <linux/kthread.h> | 14 | #include <linux/kthread.h> |
15 | #include <linux/i2c.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/delay.h> | ||
15 | 18 | ||
16 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
17 | #include <asm/prom.h> | 20 | #include <asm/prom.h> |
@@ -27,6 +30,18 @@ static __initdata struct of_device_id warp_of_bus[] = { | |||
27 | {}, | 30 | {}, |
28 | }; | 31 | }; |
29 | 32 | ||
33 | static __initdata struct i2c_board_info warp_i2c_info[] = { | ||
34 | { I2C_BOARD_INFO("ad7414", 0x4a) } | ||
35 | }; | ||
36 | |||
37 | static int __init warp_arch_init(void) | ||
38 | { | ||
39 | /* This should go away once support is moved to the dts. */ | ||
40 | i2c_register_board_info(0, warp_i2c_info, ARRAY_SIZE(warp_i2c_info)); | ||
41 | return 0; | ||
42 | } | ||
43 | machine_arch_initcall(warp, warp_arch_init); | ||
44 | |||
30 | static int __init warp_device_probe(void) | 45 | static int __init warp_device_probe(void) |
31 | { | 46 | { |
32 | of_platform_bus_probe(NULL, warp_of_bus, NULL); | 47 | of_platform_bus_probe(NULL, warp_of_bus, NULL); |
@@ -52,61 +67,232 @@ define_machine(warp) { | |||
52 | }; | 67 | }; |
53 | 68 | ||
54 | 69 | ||
55 | #define LED_GREEN (0x80000000 >> 0) | 70 | /* I am not sure this is the best place for this... */ |
56 | #define LED_RED (0x80000000 >> 1) | 71 | static int __init warp_post_info(void) |
72 | { | ||
73 | struct device_node *np; | ||
74 | void __iomem *fpga; | ||
75 | u32 post1, post2; | ||
76 | |||
77 | /* Sighhhh... POST information is in the sd area. */ | ||
78 | np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd"); | ||
79 | if (np == NULL) | ||
80 | return -ENOENT; | ||
81 | |||
82 | fpga = of_iomap(np, 0); | ||
83 | of_node_put(np); | ||
84 | if (fpga == NULL) | ||
85 | return -ENOENT; | ||
86 | |||
87 | post1 = in_be32(fpga + 0x40); | ||
88 | post2 = in_be32(fpga + 0x44); | ||
89 | |||
90 | iounmap(fpga); | ||
91 | |||
92 | if (post1 || post2) | ||
93 | printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2); | ||
94 | else | ||
95 | printk(KERN_INFO "Warp POST OK\n"); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | machine_late_initcall(warp, warp_post_info); | ||
100 | |||
101 | |||
102 | #ifdef CONFIG_SENSORS_AD7414 | ||
103 | |||
104 | static LIST_HEAD(dtm_shutdown_list); | ||
105 | static void __iomem *dtm_fpga; | ||
106 | static void __iomem *gpio_base; | ||
107 | |||
108 | |||
109 | struct dtm_shutdown { | ||
110 | struct list_head list; | ||
111 | void (*func)(void *arg); | ||
112 | void *arg; | ||
113 | }; | ||
57 | 114 | ||
58 | 115 | ||
59 | /* This is for the power LEDs 1 = on, 0 = off, -1 = leave alone */ | 116 | int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) |
60 | void warp_set_power_leds(int green, int red) | ||
61 | { | 117 | { |
62 | static void __iomem *gpio_base = NULL; | 118 | struct dtm_shutdown *shutdown; |
63 | unsigned leds; | 119 | |
64 | 120 | shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL); | |
65 | if (gpio_base == NULL) { | 121 | if (shutdown == NULL) |
66 | struct device_node *np; | 122 | return -ENOMEM; |
67 | 123 | ||
68 | /* Power LEDS are on the second GPIO controller */ | 124 | shutdown->func = func; |
69 | np = of_find_compatible_node(NULL, NULL, "ibm,gpio-440EP"); | 125 | shutdown->arg = arg; |
70 | if (np) | 126 | |
71 | np = of_find_compatible_node(np, NULL, "ibm,gpio-440EP"); | 127 | list_add(&shutdown->list, &dtm_shutdown_list); |
72 | if (np == NULL) { | 128 | |
73 | printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); | 129 | return 0; |
74 | return; | 130 | } |
131 | |||
132 | int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) | ||
133 | { | ||
134 | struct dtm_shutdown *shutdown; | ||
135 | |||
136 | list_for_each_entry(shutdown, &dtm_shutdown_list, list) | ||
137 | if (shutdown->func == func && shutdown->arg == arg) { | ||
138 | list_del(&shutdown->list); | ||
139 | kfree(shutdown); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | static irqreturn_t temp_isr(int irq, void *context) | ||
147 | { | ||
148 | struct dtm_shutdown *shutdown; | ||
149 | |||
150 | local_irq_disable(); | ||
151 | |||
152 | /* Run through the shutdown list. */ | ||
153 | list_for_each_entry(shutdown, &dtm_shutdown_list, list) | ||
154 | shutdown->func(shutdown->arg); | ||
155 | |||
156 | printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n"); | ||
157 | |||
158 | while (1) { | ||
159 | if (dtm_fpga) { | ||
160 | unsigned reset = in_be32(dtm_fpga + 0x14); | ||
161 | out_be32(dtm_fpga + 0x14, reset); | ||
75 | } | 162 | } |
76 | 163 | ||
77 | gpio_base = of_iomap(np, 0); | 164 | if (gpio_base) { |
78 | of_node_put(np); | 165 | unsigned leds = in_be32(gpio_base); |
79 | if (gpio_base == NULL) { | 166 | |
80 | printk(KERN_ERR __FILE__ ": Unable to map gpio"); | 167 | /* green off, red toggle */ |
81 | return; | 168 | leds &= ~0x80000000; |
169 | leds ^= 0x40000000; | ||
170 | |||
171 | out_be32(gpio_base, leds); | ||
82 | } | 172 | } |
173 | |||
174 | mdelay(500); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | static int pika_setup_leds(void) | ||
179 | { | ||
180 | struct device_node *np; | ||
181 | const u32 *gpios; | ||
182 | int len; | ||
183 | |||
184 | np = of_find_compatible_node(NULL, NULL, "linux,gpio-led"); | ||
185 | if (!np) { | ||
186 | printk(KERN_ERR __FILE__ ": Unable to find gpio-led\n"); | ||
187 | return -ENOENT; | ||
83 | } | 188 | } |
84 | 189 | ||
85 | leds = in_be32(gpio_base); | 190 | gpios = of_get_property(np, "gpios", &len); |
191 | of_node_put(np); | ||
192 | if (!gpios || len < 4) { | ||
193 | printk(KERN_ERR __FILE__ | ||
194 | ": Unable to get gpios property (%d)\n", len); | ||
195 | return -ENOENT; | ||
196 | } | ||
86 | 197 | ||
87 | switch (green) { | 198 | np = of_find_node_by_phandle(gpios[0]); |
88 | case 0: leds &= ~LED_GREEN; break; | 199 | if (!np) { |
89 | case 1: leds |= LED_GREEN; break; | 200 | printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); |
201 | return -ENOENT; | ||
90 | } | 202 | } |
91 | switch (red) { | 203 | |
92 | case 0: leds &= ~LED_RED; break; | 204 | gpio_base = of_iomap(np, 0); |
93 | case 1: leds |= LED_RED; break; | 205 | of_node_put(np); |
206 | if (!gpio_base) { | ||
207 | printk(KERN_ERR __FILE__ ": Unable to map gpio"); | ||
208 | return -ENOMEM; | ||
94 | } | 209 | } |
95 | 210 | ||
96 | out_be32(gpio_base, leds); | 211 | return 0; |
97 | } | 212 | } |
98 | EXPORT_SYMBOL(warp_set_power_leds); | ||
99 | 213 | ||
214 | static void pika_setup_critical_temp(struct i2c_client *client) | ||
215 | { | ||
216 | struct device_node *np; | ||
217 | int irq, rc; | ||
218 | |||
219 | /* Do this before enabling critical temp interrupt since we | ||
220 | * may immediately interrupt. | ||
221 | */ | ||
222 | pika_setup_leds(); | ||
223 | |||
224 | /* These registers are in 1 degree increments. */ | ||
225 | i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */ | ||
226 | i2c_smbus_write_byte_data(client, 3, 55); /* Tlow */ | ||
227 | |||
228 | np = of_find_compatible_node(NULL, NULL, "adi,ad7414"); | ||
229 | if (np == NULL) { | ||
230 | printk(KERN_ERR __FILE__ ": Unable to find ad7414\n"); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | irq = irq_of_parse_and_map(np, 0); | ||
235 | of_node_put(np); | ||
236 | if (irq == NO_IRQ) { | ||
237 | printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n"); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | rc = request_irq(irq, temp_isr, 0, "ad7414", NULL); | ||
242 | if (rc) { | ||
243 | printk(KERN_ERR __FILE__ | ||
244 | ": Unable to request ad7414 irq %d = %d\n", irq, rc); | ||
245 | return; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static inline void pika_dtm_check_fan(void __iomem *fpga) | ||
250 | { | ||
251 | static int fan_state; | ||
252 | u32 fan = in_be32(fpga + 0x34) & (1 << 14); | ||
253 | |||
254 | if (fan_state != fan) { | ||
255 | fan_state = fan; | ||
256 | if (fan) | ||
257 | printk(KERN_WARNING "Fan rotation error detected." | ||
258 | " Please check hardware.\n"); | ||
259 | } | ||
260 | } | ||
100 | 261 | ||
101 | #ifdef CONFIG_SENSORS_AD7414 | ||
102 | static int pika_dtm_thread(void __iomem *fpga) | 262 | static int pika_dtm_thread(void __iomem *fpga) |
103 | { | 263 | { |
104 | extern int ad7414_get_temp(int index); | 264 | struct i2c_adapter *adap; |
265 | struct i2c_client *client; | ||
266 | |||
267 | /* We loop in case either driver was compiled as a module and | ||
268 | * has not been insmoded yet. | ||
269 | */ | ||
270 | while (!(adap = i2c_get_adapter(0))) { | ||
271 | set_current_state(TASK_INTERRUPTIBLE); | ||
272 | schedule_timeout(HZ); | ||
273 | } | ||
274 | |||
275 | while (1) { | ||
276 | list_for_each_entry(client, &adap->clients, list) | ||
277 | if (client->addr == 0x4a) | ||
278 | goto found_it; | ||
279 | |||
280 | set_current_state(TASK_INTERRUPTIBLE); | ||
281 | schedule_timeout(HZ); | ||
282 | } | ||
283 | |||
284 | found_it: | ||
285 | i2c_put_adapter(adap); | ||
286 | |||
287 | pika_setup_critical_temp(client); | ||
288 | |||
289 | printk(KERN_INFO "PIKA DTM thread running.\n"); | ||
105 | 290 | ||
106 | while (!kthread_should_stop()) { | 291 | while (!kthread_should_stop()) { |
107 | int temp = ad7414_get_temp(0); | 292 | u16 temp = swab16(i2c_smbus_read_word_data(client, 0)); |
293 | out_be32(fpga + 0x20, temp); | ||
108 | 294 | ||
109 | out_be32(fpga, temp); | 295 | pika_dtm_check_fan(fpga); |
110 | 296 | ||
111 | set_current_state(TASK_INTERRUPTIBLE); | 297 | set_current_state(TASK_INTERRUPTIBLE); |
112 | schedule_timeout(HZ); | 298 | schedule_timeout(HZ); |
@@ -115,37 +301,44 @@ static int pika_dtm_thread(void __iomem *fpga) | |||
115 | return 0; | 301 | return 0; |
116 | } | 302 | } |
117 | 303 | ||
304 | |||
118 | static int __init pika_dtm_start(void) | 305 | static int __init pika_dtm_start(void) |
119 | { | 306 | { |
120 | struct task_struct *dtm_thread; | 307 | struct task_struct *dtm_thread; |
121 | struct device_node *np; | 308 | struct device_node *np; |
122 | struct resource res; | ||
123 | void __iomem *fpga; | ||
124 | 309 | ||
125 | np = of_find_compatible_node(NULL, NULL, "pika,fpga"); | 310 | np = of_find_compatible_node(NULL, NULL, "pika,fpga"); |
126 | if (np == NULL) | 311 | if (np == NULL) |
127 | return -ENOENT; | 312 | return -ENOENT; |
128 | 313 | ||
129 | /* We do not call of_iomap here since it would map in the entire | 314 | dtm_fpga = of_iomap(np, 0); |
130 | * fpga space, which is over 8k. | ||
131 | */ | ||
132 | if (of_address_to_resource(np, 0, &res)) { | ||
133 | of_node_put(np); | ||
134 | return -ENOENT; | ||
135 | } | ||
136 | of_node_put(np); | 315 | of_node_put(np); |
137 | 316 | if (dtm_fpga == NULL) | |
138 | fpga = ioremap(res.start, 0x24); | ||
139 | if (fpga == NULL) | ||
140 | return -ENOENT; | 317 | return -ENOENT; |
141 | 318 | ||
142 | dtm_thread = kthread_run(pika_dtm_thread, fpga + 0x20, "pika-dtm"); | 319 | dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm"); |
143 | if (IS_ERR(dtm_thread)) { | 320 | if (IS_ERR(dtm_thread)) { |
144 | iounmap(fpga); | 321 | iounmap(dtm_fpga); |
145 | return PTR_ERR(dtm_thread); | 322 | return PTR_ERR(dtm_thread); |
146 | } | 323 | } |
147 | 324 | ||
148 | return 0; | 325 | return 0; |
149 | } | 326 | } |
150 | device_initcall(pika_dtm_start); | 327 | machine_late_initcall(warp, pika_dtm_start); |
328 | |||
329 | #else /* !CONFIG_SENSORS_AD7414 */ | ||
330 | |||
331 | int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg) | ||
332 | { | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg) | ||
337 | { | ||
338 | return 0; | ||
339 | } | ||
340 | |||
151 | #endif | 341 | #endif |
342 | |||
343 | EXPORT_SYMBOL(pika_dtm_register_shutdown); | ||
344 | EXPORT_SYMBOL(pika_dtm_unregister_shutdown); | ||