linux/arch/powerpc/platforms/44x/warp.c
<<
>>
Prefs
   1/*
   2 * PIKA Warp(tm) board specific routines
   3 *
   4 * Copyright (c) 2008 PIKA Technologies
   5 *   Sean MacLennan <smaclennan@pikatech.com>
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 */
  12#include <linux/init.h>
  13#include <linux/of_platform.h>
  14#include <linux/kthread.h>
  15#include <linux/i2c.h>
  16#include <linux/interrupt.h>
  17#include <linux/delay.h>
  18
  19#include <asm/machdep.h>
  20#include <asm/prom.h>
  21#include <asm/udbg.h>
  22#include <asm/time.h>
  23#include <asm/uic.h>
  24#include <asm/ppc4xx.h>
  25
  26static __initdata struct of_device_id warp_of_bus[] = {
  27        { .compatible = "ibm,plb4", },
  28        { .compatible = "ibm,opb", },
  29        { .compatible = "ibm,ebc", },
  30        {},
  31};
  32
  33static int __init warp_device_probe(void)
  34{
  35        of_platform_bus_probe(NULL, warp_of_bus, NULL);
  36        return 0;
  37}
  38machine_device_initcall(warp, warp_device_probe);
  39
  40static int __init warp_probe(void)
  41{
  42        unsigned long root = of_get_flat_dt_root();
  43
  44        return of_flat_dt_is_compatible(root, "pika,warp");
  45}
  46
  47define_machine(warp) {
  48        .name           = "Warp",
  49        .probe          = warp_probe,
  50        .progress       = udbg_progress,
  51        .init_IRQ       = uic_init_tree,
  52        .get_irq        = uic_get_irq,
  53        .restart        = ppc4xx_reset_system,
  54        .calibrate_decr = generic_calibrate_decr,
  55};
  56
  57
  58/* I am not sure this is the best place for this... */
  59static int __init warp_post_info(void)
  60{
  61        struct device_node *np;
  62        void __iomem *fpga;
  63        u32 post1, post2;
  64
  65        /* Sighhhh... POST information is in the sd area. */
  66        np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
  67        if (np == NULL)
  68                return -ENOENT;
  69
  70        fpga = of_iomap(np, 0);
  71        of_node_put(np);
  72        if (fpga == NULL)
  73                return -ENOENT;
  74
  75        post1 = in_be32(fpga + 0x40);
  76        post2 = in_be32(fpga + 0x44);
  77
  78        iounmap(fpga);
  79
  80        if (post1 || post2)
  81                printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2);
  82        else
  83                printk(KERN_INFO "Warp POST OK\n");
  84
  85        return 0;
  86}
  87machine_late_initcall(warp, warp_post_info);
  88
  89
  90#ifdef CONFIG_SENSORS_AD7414
  91
  92static LIST_HEAD(dtm_shutdown_list);
  93static void __iomem *dtm_fpga;
  94static void __iomem *gpio_base;
  95
  96
  97struct dtm_shutdown {
  98        struct list_head list;
  99        void (*func)(void *arg);
 100        void *arg;
 101};
 102
 103
 104int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg)
 105{
 106        struct dtm_shutdown *shutdown;
 107
 108        shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL);
 109        if (shutdown == NULL)
 110                return -ENOMEM;
 111
 112        shutdown->func = func;
 113        shutdown->arg = arg;
 114
 115        list_add(&shutdown->list, &dtm_shutdown_list);
 116
 117        return 0;
 118}
 119
 120int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg)
 121{
 122        struct dtm_shutdown *shutdown;
 123
 124        list_for_each_entry(shutdown, &dtm_shutdown_list, list)
 125                if (shutdown->func == func && shutdown->arg == arg) {
 126                        list_del(&shutdown->list);
 127                        kfree(shutdown);
 128                        return 0;
 129                }
 130
 131        return -EINVAL;
 132}
 133
 134static irqreturn_t temp_isr(int irq, void *context)
 135{
 136        struct dtm_shutdown *shutdown;
 137
 138        local_irq_disable();
 139
 140        /* Run through the shutdown list. */
 141        list_for_each_entry(shutdown, &dtm_shutdown_list, list)
 142                shutdown->func(shutdown->arg);
 143
 144        printk(KERN_EMERG "\n\nCritical Temperature Shutdown\n");
 145
 146        while (1) {
 147                if (dtm_fpga) {
 148                        unsigned reset = in_be32(dtm_fpga + 0x14);
 149                        out_be32(dtm_fpga + 0x14, reset);
 150                }
 151
 152                if (gpio_base) {
 153                        unsigned leds = in_be32(gpio_base);
 154
 155                        /* green off, red toggle */
 156                        leds &= ~0x80000000;
 157                        leds ^=  0x40000000;
 158
 159                        out_be32(gpio_base, leds);
 160                }
 161
 162                mdelay(500);
 163        }
 164}
 165
 166static int pika_setup_leds(void)
 167{
 168        struct device_node *np;
 169        const u32 *gpios;
 170        int len;
 171
 172        np = of_find_compatible_node(NULL, NULL, "linux,gpio-led");
 173        if (!np) {
 174                printk(KERN_ERR __FILE__ ": Unable to find gpio-led\n");
 175                return -ENOENT;
 176        }
 177
 178        gpios = of_get_property(np, "gpios", &len);
 179        of_node_put(np);
 180        if (!gpios || len < 4) {
 181                printk(KERN_ERR __FILE__
 182                       ": Unable to get gpios property (%d)\n", len);
 183                return -ENOENT;
 184        }
 185
 186        np = of_find_node_by_phandle(gpios[0]);
 187        if (!np) {
 188                printk(KERN_ERR __FILE__ ": Unable to find gpio\n");
 189                return -ENOENT;
 190        }
 191
 192        gpio_base = of_iomap(np, 0);
 193        of_node_put(np);
 194        if (!gpio_base) {
 195                printk(KERN_ERR __FILE__ ": Unable to map gpio");
 196                return -ENOMEM;
 197        }
 198
 199        return 0;
 200}
 201
 202static void pika_setup_critical_temp(struct i2c_client *client)
 203{
 204        struct device_node *np;
 205        int irq, rc;
 206
 207        /* Do this before enabling critical temp interrupt since we
 208         * may immediately interrupt.
 209         */
 210        pika_setup_leds();
 211
 212        /* These registers are in 1 degree increments. */
 213        i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */
 214        i2c_smbus_write_byte_data(client, 3,  0); /* Tlow */
 215
 216        np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
 217        if (np == NULL) {
 218                printk(KERN_ERR __FILE__ ": Unable to find ad7414\n");
 219                return;
 220        }
 221
 222        irq = irq_of_parse_and_map(np, 0);
 223        of_node_put(np);
 224        if (irq  == NO_IRQ) {
 225                printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
 226                return;
 227        }
 228
 229        rc = request_irq(irq, temp_isr, 0, "ad7414", NULL);
 230        if (rc) {
 231                printk(KERN_ERR __FILE__
 232                       ": Unable to request ad7414 irq %d = %d\n", irq, rc);
 233                return;
 234        }
 235}
 236
 237static inline void pika_dtm_check_fan(void __iomem *fpga)
 238{
 239        static int fan_state;
 240        u32 fan = in_be32(fpga + 0x34) & (1 << 14);
 241
 242        if (fan_state != fan) {
 243                fan_state = fan;
 244                if (fan)
 245                        printk(KERN_WARNING "Fan rotation error detected."
 246                                   " Please check hardware.\n");
 247        }
 248}
 249
 250static int pika_dtm_thread(void __iomem *fpga)
 251{
 252        struct i2c_adapter *adap;
 253        struct i2c_client *client;
 254
 255        /* We loop in case either driver was compiled as a module and
 256         * has not been insmoded yet.
 257         */
 258        while (!(adap = i2c_get_adapter(0))) {
 259                set_current_state(TASK_INTERRUPTIBLE);
 260                schedule_timeout(HZ);
 261        }
 262
 263        while (1) {
 264                list_for_each_entry(client, &adap->clients, list)
 265                        if (client->addr == 0x4a)
 266                                goto found_it;
 267
 268                set_current_state(TASK_INTERRUPTIBLE);
 269                schedule_timeout(HZ);
 270        }
 271
 272found_it:
 273        i2c_put_adapter(adap);
 274
 275        pika_setup_critical_temp(client);
 276
 277        printk(KERN_INFO "PIKA DTM thread running.\n");
 278
 279        while (!kthread_should_stop()) {
 280                int val;
 281
 282                val = i2c_smbus_read_word_data(client, 0);
 283                if (val < 0)
 284                        dev_dbg(&client->dev, "DTM read temp failed.\n");
 285                else {
 286                        s16 temp = swab16(val);
 287                        out_be32(fpga + 0x20, temp);
 288                }
 289
 290                pika_dtm_check_fan(fpga);
 291
 292                set_current_state(TASK_INTERRUPTIBLE);
 293                schedule_timeout(HZ);
 294        }
 295
 296        return 0;
 297}
 298
 299
 300static int __init pika_dtm_start(void)
 301{
 302        struct task_struct *dtm_thread;
 303        struct device_node *np;
 304
 305        np = of_find_compatible_node(NULL, NULL, "pika,fpga");
 306        if (np == NULL)
 307                return -ENOENT;
 308
 309        dtm_fpga = of_iomap(np, 0);
 310        of_node_put(np);
 311        if (dtm_fpga == NULL)
 312                return -ENOENT;
 313
 314        dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm");
 315        if (IS_ERR(dtm_thread)) {
 316                iounmap(dtm_fpga);
 317                return PTR_ERR(dtm_thread);
 318        }
 319
 320        return 0;
 321}
 322machine_late_initcall(warp, pika_dtm_start);
 323
 324#else /* !CONFIG_SENSORS_AD7414 */
 325
 326int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg)
 327{
 328        return 0;
 329}
 330
 331int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg)
 332{
 333        return 0;
 334}
 335
 336#endif
 337
 338EXPORT_SYMBOL(pika_dtm_register_shutdown);
 339EXPORT_SYMBOL(pika_dtm_unregister_shutdown);
 340
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.