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