linux/drivers/mfd/tps65910-irq.c
<<
>>
Prefs
   1/*
   2 * tps65910-irq.c  --  TI TPS6591x
   3 *
   4 * Copyright 2010 Texas Instruments Inc.
   5 *
   6 * Author: Graeme Gregory <gg@slimlogic.co.uk>
   7 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify it
  10 *  under  the terms of the GNU General  Public License as published by the
  11 *  Free Software Foundation;  either version 2 of the License, or (at your
  12 *  option) any later version.
  13 *
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/init.h>
  19#include <linux/bug.h>
  20#include <linux/device.h>
  21#include <linux/interrupt.h>
  22#include <linux/irq.h>
  23#include <linux/gpio.h>
  24#include <linux/mfd/tps65910.h>
  25
  26static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
  27                                                        int irq)
  28{
  29        return (irq - tps65910->irq_base);
  30}
  31
  32/*
  33 * This is a threaded IRQ handler so can access I2C/SPI.  Since all
  34 * interrupts are clear on read the IRQ line will be reasserted and
  35 * the physical IRQ will be handled again if another interrupt is
  36 * asserted while we run - in the normal course of events this is a
  37 * rare occurrence so we save I2C/SPI reads.  We're also assuming that
  38 * it's rare to get lots of interrupts firing simultaneously so try to
  39 * minimise I/O.
  40 */
  41static irqreturn_t tps65910_irq(int irq, void *irq_data)
  42{
  43        struct tps65910 *tps65910 = irq_data;
  44        u32 irq_sts;
  45        u32 irq_mask;
  46        u8 reg;
  47        int i;
  48
  49        tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
  50        irq_sts = reg;
  51        tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
  52        irq_sts |= reg << 8;
  53        switch (tps65910_chip_id(tps65910)) {
  54        case TPS65911:
  55                tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
  56                irq_sts |= reg << 16;
  57        }
  58
  59        tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
  60        irq_mask = reg;
  61        tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
  62        irq_mask |= reg << 8;
  63        switch (tps65910_chip_id(tps65910)) {
  64        case TPS65911:
  65                tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
  66                irq_mask |= reg << 16;
  67        }
  68
  69        irq_sts &= ~irq_mask;
  70
  71        if (!irq_sts)
  72                return IRQ_NONE;
  73
  74        for (i = 0; i < tps65910->irq_num; i++) {
  75
  76                if (!(irq_sts & (1 << i)))
  77                        continue;
  78
  79                handle_nested_irq(tps65910->irq_base + i);
  80        }
  81
  82        /* Write the STS register back to clear IRQs we handled */
  83        reg = irq_sts & 0xFF;
  84        irq_sts >>= 8;
  85        tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
  86        reg = irq_sts & 0xFF;
  87        tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
  88        switch (tps65910_chip_id(tps65910)) {
  89        case TPS65911:
  90                reg = irq_sts >> 8;
  91                tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
  92        }
  93
  94        return IRQ_HANDLED;
  95}
  96
  97static void tps65910_irq_lock(struct irq_data *data)
  98{
  99        struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
 100
 101        mutex_lock(&tps65910->irq_lock);
 102}
 103
 104static void tps65910_irq_sync_unlock(struct irq_data *data)
 105{
 106        struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
 107        u32 reg_mask;
 108        u8 reg;
 109
 110        tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
 111        reg_mask = reg;
 112        tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
 113        reg_mask |= reg << 8;
 114        switch (tps65910_chip_id(tps65910)) {
 115        case TPS65911:
 116                tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
 117                reg_mask |= reg << 16;
 118        }
 119
 120        if (tps65910->irq_mask != reg_mask) {
 121                reg = tps65910->irq_mask & 0xFF;
 122                tps65910->write(tps65910, TPS65910_INT_MSK, 1, &reg);
 123                reg = tps65910->irq_mask >> 8 & 0xFF;
 124                tps65910->write(tps65910, TPS65910_INT_MSK2, 1, &reg);
 125                switch (tps65910_chip_id(tps65910)) {
 126                case TPS65911:
 127                        reg = tps65910->irq_mask >> 16;
 128                        tps65910->write(tps65910, TPS65910_INT_MSK3, 1, &reg);
 129                }
 130        }
 131        mutex_unlock(&tps65910->irq_lock);
 132}
 133
 134static void tps65910_irq_enable(struct irq_data *data)
 135{
 136        struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
 137
 138        tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 139}
 140
 141static void tps65910_irq_disable(struct irq_data *data)
 142{
 143        struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
 144
 145        tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 146}
 147
 148#ifdef CONFIG_PM_SLEEP
 149static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
 150{
 151        struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
 152        return irq_set_irq_wake(tps65910->chip_irq, enable);
 153}
 154#else
 155#define tps65910_irq_set_wake NULL
 156#endif
 157
 158static struct irq_chip tps65910_irq_chip = {
 159        .name = "tps65910",
 160        .irq_bus_lock = tps65910_irq_lock,
 161        .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
 162        .irq_disable = tps65910_irq_disable,
 163        .irq_enable = tps65910_irq_enable,
 164        .irq_set_wake = tps65910_irq_set_wake,
 165};
 166
 167int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 168                    struct tps65910_platform_data *pdata)
 169{
 170        int ret, cur_irq;
 171        int flags = IRQF_ONESHOT;
 172
 173        if (!irq) {
 174                dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
 175                return -EINVAL;
 176        }
 177
 178        if (!pdata || !pdata->irq_base) {
 179                dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
 180                return -EINVAL;
 181        }
 182
 183        tps65910->irq_mask = 0xFFFFFF;
 184
 185        mutex_init(&tps65910->irq_lock);
 186        tps65910->chip_irq = irq;
 187        tps65910->irq_base = pdata->irq_base;
 188
 189        switch (tps65910_chip_id(tps65910)) {
 190        case TPS65910:
 191                tps65910->irq_num = TPS65910_NUM_IRQ;
 192                break;
 193        case TPS65911:
 194                tps65910->irq_num = TPS65911_NUM_IRQ;
 195                break;
 196        }
 197
 198        /* Register with genirq */
 199        for (cur_irq = tps65910->irq_base;
 200             cur_irq < tps65910->irq_num + tps65910->irq_base;
 201             cur_irq++) {
 202                irq_set_chip_data(cur_irq, tps65910);
 203                irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip,
 204                                         handle_edge_irq);
 205                irq_set_nested_thread(cur_irq, 1);
 206
 207                /* ARM needs us to explicitly flag the IRQ as valid
 208                 * and will set them noprobe when we do so. */
 209#ifdef CONFIG_ARM
 210                set_irq_flags(cur_irq, IRQF_VALID);
 211#else
 212                irq_set_noprobe(cur_irq);
 213#endif
 214        }
 215
 216        ret = request_threaded_irq(irq, NULL, tps65910_irq, flags,
 217                                   "tps65910", tps65910);
 218
 219        irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
 220
 221        if (ret != 0)
 222                dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret);
 223
 224        return ret;
 225}
 226
 227int tps65910_irq_exit(struct tps65910 *tps65910)
 228{
 229        if (tps65910->chip_irq)
 230                free_irq(tps65910->chip_irq, tps65910);
 231        return 0;
 232}
 233