linux/arch/powerpc/platforms/44x/warp.c
<<
>>
Prefs
   1/*
   2 * PIKA Warp(tm) board specific routines
   3 *
   4 * Copyright (c) 2008-2009 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#include <linux/of_gpio.h>
  19#include <linux/slab.h>
  20#include <linux/export.h>
  21
  22#include <asm/machdep.h>
  23#include <asm/prom.h>
  24#include <asm/udbg.h>
  25#include <asm/time.h>
  26#include <asm/uic.h>
  27#include <asm/ppc4xx.h>
  28#include <asm/dma.h>
  29
  30
  31static const struct of_device_id warp_of_bus[] __initconst = {
  32        { .compatible = "ibm,plb4", },
  33        { .compatible = "ibm,opb", },
  34        { .compatible = "ibm,ebc", },
  35        {},
  36};
  37
  38static int __init warp_device_probe(void)
  39{
  40        of_platform_bus_probe(NULL, warp_of_bus, NULL);
  41        return 0;
  42}
  43machine_device_initcall(warp, warp_device_probe);
  44
  45static int __init warp_probe(void)
  46{
  47        unsigned long root = of_get_flat_dt_root();
  48
  49        if (!of_flat_dt_is_compatible(root, "pika,warp"))
  50                return 0;
  51
  52        /* For __dma_alloc_coherent */
  53        ISA_DMA_THRESHOLD = ~0L;
  54
  55        return 1;
  56}
  57
  58define_machine(warp) {
  59        .name           = "Warp",
  60        .probe          = warp_probe,
  61        .progress       = udbg_progress,
  62        .init_IRQ       = uic_init_tree,
  63        .get_irq        = uic_get_irq,
  64        .restart        = ppc4xx_reset_system,
  65        .calibrate_decr = generic_calibrate_decr,
  66};
  67
  68
  69static int __init warp_post_info(void)
  70{
  71        struct device_node *np;
  72        void __iomem *fpga;
  73        u32 post1, post2;
  74
  75        /* Sighhhh... POST information is in the sd area. */
  76        np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
  77        if (np == NULL)
  78                return -ENOENT;
  79
  80        fpga = of_iomap(np, 0);
  81        of_node_put(np);
  82        if (fpga == NULL)
  83                return -ENOENT;
  84
  85        post1 = in_be32(fpga + 0x40);
  86        post2 = in_be32(fpga + 0x44);
  87
  88        iounmap(fpga);
  89
  90        if (post1 || post2)
  91                printk(KERN_INFO "Warp POST %08x %08x\n", post1, post2);
  92        else
  93                printk(KERN_INFO "Warp POST OK\n");
  94
  95        return 0;
  96}
  97
  98
  99#ifdef CONFIG_SENSORS_AD7414
 100
 101static LIST_HEAD(dtm_shutdown_list);
 102static void __iomem *dtm_fpga;
 103static unsigned green_led, red_led;
 104
 105
 106struct dtm_shutdown {
 107        struct list_head list;
 108        void (*func)(void *arg);
 109        void *arg;
 110};
 111
 112
 113int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg)
 114{
 115        struct dtm_shutdown *shutdown;
 116
 117        shutdown = kmalloc(sizeof(struct dtm_shutdown), GFP_KERNEL);
 118        if (shutdown == NULL)
 119                return -ENOMEM;
 120
 121        shutdown->func = func;
 122        shutdown->arg = arg;
 123
 124        list_add(&shutdown->list, &dtm_shutdown_list);
 125
 126        return 0;
 127}
 128
 129int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg)
 130{
 131        struct dtm_shutdown *shutdown;
 132
 133        list_for_each_entry(shutdown, &dtm_shutdown_list, list)
 134                if (shutdown->func == func && shutdown->arg == arg) {
 135                        list_del(&shutdown->list);
 136                        kfree(shutdown);
 137                        return 0;
 138                }
 139
 140        return -EINVAL;
 141}
 142
 143static irqreturn_t temp_isr(int irq, void *context)
 144{
 145        struct dtm_shutdown *shutdown;
 146        int value = 1;
 147
 148        local_irq_disable();
 149
 150        gpio_set_value(green_led, 0);
 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\n");
 157
 158        while (1) {
 159                if (dtm_fpga) {
 160                        unsigned reset = in_be32(dtm_fpga + 0x14);
 161                        out_be32(dtm_fpga + 0x14, reset);
 162                }
 163
 164                gpio_set_value(red_led, value);
 165                value ^= 1;
 166                mdelay(500);
 167        }
 168
 169        /* Not reached */
 170        return IRQ_HANDLED;
 171}
 172
 173static int pika_setup_leds(void)
 174{
 175        struct device_node *np, *child;
 176
 177        np = of_find_compatible_node(NULL, NULL, "gpio-leds");
 178        if (!np) {
 179                printk(KERN_ERR __FILE__ ": Unable to find leds\n");
 180                return -ENOENT;
 181        }
 182
 183        for_each_child_of_node(np, child)
 184                if (strcmp(child->name, "green") == 0)
 185                        green_led = of_get_gpio(child, 0);
 186                else if (strcmp(child->name, "red") == 0)
 187                        red_led = of_get_gpio(child, 0);
 188
 189        of_node_put(np);
 190
 191        return 0;
 192}
 193
 194static void pika_setup_critical_temp(struct device_node *np,
 195                                     struct i2c_client *client)
 196{
 197        int irq, rc;
 198
 199        /* Do this before enabling critical temp interrupt since we
 200         * may immediately interrupt.
 201         */
 202        pika_setup_leds();
 203
 204        /* These registers are in 1 degree increments. */
 205        i2c_smbus_write_byte_data(client, 2, 65); /* Thigh */
 206        i2c_smbus_write_byte_data(client, 3,  0); /* Tlow */
 207
 208        irq = irq_of_parse_and_map(np, 0);
 209        if (irq  == NO_IRQ) {
 210                printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n");
 211                return;
 212        }
 213
 214        rc = request_irq(irq, temp_isr, 0, "ad7414", NULL);
 215        if (rc) {
 216                printk(KERN_ERR __FILE__
 217                       ": Unable to request ad7414 irq %d = %d\n", irq, rc);
 218                return;
 219        }
 220}
 221
 222static inline void pika_dtm_check_fan(void __iomem *fpga)
 223{
 224        static int fan_state;
 225        u32 fan = in_be32(fpga + 0x34) & (1 << 14);
 226
 227        if (fan_state != fan) {
 228                fan_state = fan;
 229                if (fan)
 230                        printk(KERN_WARNING "Fan rotation error detected."
 231                                   " Please check hardware.\n");
 232        }
 233}
 234
 235static int pika_dtm_thread(void __iomem *fpga)
 236{
 237        struct device_node *np;
 238        struct i2c_client *client;
 239
 240        np = of_find_compatible_node(NULL, NULL, "adi,ad7414");
 241        if (np == NULL)
 242                return -ENOENT;
 243
 244        client = of_find_i2c_device_by_node(np);
 245        if (client == NULL) {
 246                of_node_put(np);
 247                return -ENOENT;
 248        }
 249
 250        pika_setup_critical_temp(np, client);
 251
 252        of_node_put(np);
 253
 254        printk(KERN_INFO "Warp DTM thread running.\n");
 255
 256        while (!kthread_should_stop()) {
 257                int val;
 258
 259                val = i2c_smbus_read_word_data(client, 0);
 260                if (val < 0)
 261                        dev_dbg(&client->dev, "DTM read temp failed.\n");
 262                else {
 263                        s16 temp = swab16(val);
 264                        out_be32(fpga + 0x20, temp);
 265                }
 266
 267                pika_dtm_check_fan(fpga);
 268
 269                set_current_state(TASK_INTERRUPTIBLE);
 270                schedule_timeout(HZ);
 271        }
 272
 273        return 0;
 274}
 275
 276static int __init pika_dtm_start(void)
 277{
 278        struct task_struct *dtm_thread;
 279        struct device_node *np;
 280
 281        np = of_find_compatible_node(NULL, NULL, "pika,fpga");
 282        if (np == NULL)
 283                return -ENOENT;
 284
 285        dtm_fpga = of_iomap(np, 0);
 286        of_node_put(np);
 287        if (dtm_fpga == NULL)
 288                return -ENOENT;
 289
 290        /* Must get post info before thread starts. */
 291        warp_post_info();
 292
 293        dtm_thread = kthread_run(pika_dtm_thread, dtm_fpga, "pika-dtm");
 294        if (IS_ERR(dtm_thread)) {
 295                iounmap(dtm_fpga);
 296                return PTR_ERR(dtm_thread);
 297        }
 298
 299        return 0;
 300}
 301machine_late_initcall(warp, pika_dtm_start);
 302
 303#else /* !CONFIG_SENSORS_AD7414 */
 304
 305int pika_dtm_register_shutdown(void (*func)(void *arg), void *arg)
 306{
 307        return 0;
 308}
 309
 310int pika_dtm_unregister_shutdown(void (*func)(void *arg), void *arg)
 311{
 312        return 0;
 313}
 314
 315machine_late_initcall(warp, warp_post_info);
 316
 317#endif
 318
 319EXPORT_SYMBOL(pika_dtm_register_shutdown);
 320EXPORT_SYMBOL(pika_dtm_unregister_shutdown);
 321