linux/drivers/mfd/tps65912-irq.c
<<
>>
Prefs
   1/*
   2 * tps65912-irq.c  --  TI TPS6591x
   3 *
   4 * Copyright 2011 Texas Instruments Inc.
   5 *
   6 * Author: Margarita Olaya <magi@slimlogic.co.uk>
   7 *
   8 *  This program is free software; you can redistribute it and/or modify it
   9 *  under  the terms of the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the License, or (at your
  11 *  option) any later version.
  12 *
  13 * This driver is based on wm8350 implementation.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/bug.h>
  19#include <linux/device.h>
  20#include <linux/interrupt.h>
  21#include <linux/irq.h>
  22#include <linux/gpio.h>
  23#include <linux/mfd/tps65912.h>
  24
  25static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
  26                                                        int irq)
  27{
  28        return irq - tps65912->irq_base;
  29}
  30
  31/*
  32 * This is a threaded IRQ handler so can access I2C/SPI.  Since the
  33 * IRQ handler explicitly clears the IRQ it handles the IRQ line
  34 * will be reasserted and the physical IRQ will be handled again if
  35 * another interrupt is asserted while we run - in the normal course
  36 * of events this is a rare occurrence so we save I2C/SPI reads. We're
  37 * also assuming that it's rare to get lots of interrupts firing
  38 * simultaneously so try to minimise I/O.
  39 */
  40static irqreturn_t tps65912_irq(int irq, void *irq_data)
  41{
  42        struct tps65912 *tps65912 = irq_data;
  43        u32 irq_sts;
  44        u32 irq_mask;
  45        u8 reg;
  46        int i;
  47
  48
  49        tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
  50        irq_sts = reg;
  51        tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
  52        irq_sts |= reg << 8;
  53        tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
  54        irq_sts |= reg << 16;
  55        tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
  56        irq_sts |= reg << 24;
  57
  58        tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
  59        irq_mask = reg;
  60        tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
  61        irq_mask |= reg << 8;
  62        tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
  63        irq_mask |= reg << 16;
  64        tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
  65        irq_mask |= reg << 24;
  66
  67        irq_sts &= ~irq_mask;
  68        if (!irq_sts)
  69                return IRQ_NONE;
  70
  71        for (i = 0; i < tps65912->irq_num; i++) {
  72                if (!(irq_sts & (1 << i)))
  73                        continue;
  74
  75                handle_nested_irq(tps65912->irq_base + i);
  76        }
  77
  78        /* Write the STS register back to clear IRQs we handled */
  79        reg = irq_sts & 0xFF;
  80        irq_sts >>= 8;
  81        if (reg)
  82                tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
  83        reg = irq_sts & 0xFF;
  84        irq_sts >>= 8;
  85        if (reg)
  86                tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
  87        reg = irq_sts & 0xFF;
  88        irq_sts >>= 8;
  89        if (reg)
  90                tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
  91        reg = irq_sts & 0xFF;
  92        if (reg)
  93                tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
  94
  95        return IRQ_HANDLED;
  96}
  97
  98static void tps65912_irq_lock(struct irq_data *data)
  99{
 100        struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
 101
 102        mutex_lock(&tps65912->irq_lock);
 103}
 104
 105static void tps65912_irq_sync_unlock(struct irq_data *data)
 106{
 107        struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
 108        u32 reg_mask;
 109        u8 reg;
 110
 111        tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
 112        reg_mask = reg;
 113        tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
 114        reg_mask |= reg << 8;
 115        tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
 116        reg_mask |= reg << 16;
 117        tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
 118        reg_mask |= reg << 24;
 119
 120        if (tps65912->irq_mask != reg_mask) {
 121                reg = tps65912->irq_mask & 0xFF;
 122                tps65912->write(tps65912, TPS65912_INT_MSK, 1, &reg);
 123                reg = tps65912->irq_mask >> 8 & 0xFF;
 124                tps65912->write(tps65912, TPS65912_INT_MSK2, 1, &reg);
 125                reg = tps65912->irq_mask >> 16 & 0xFF;
 126                tps65912->write(tps65912, TPS65912_INT_MSK3, 1, &reg);
 127                reg = tps65912->irq_mask >> 24 & 0xFF;
 128                tps65912->write(tps65912, TPS65912_INT_MSK4, 1, &reg);
 129        }
 130
 131        mutex_unlock(&tps65912->irq_lock);
 132}
 133
 134static void tps65912_irq_enable(struct irq_data *data)
 135{
 136        struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
 137
 138        tps65912->irq_mask &= ~(1 << irq_to_tps65912_irq(tps65912, data->irq));
 139}
 140
 141static void tps65912_irq_disable(struct irq_data *data)
 142{
 143        struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
 144
 145        tps65912->irq_mask |= (1 << irq_to_tps65912_irq(tps65912, data->irq));
 146}
 147
 148static struct irq_chip tps65912_irq_chip = {
 149        .name = "tps65912",
 150        .irq_bus_lock = tps65912_irq_lock,
 151        .irq_bus_sync_unlock = tps65912_irq_sync_unlock,
 152        .irq_disable = tps65912_irq_disable,
 153        .irq_enable = tps65912_irq_enable,
 154};
 155
 156int tps65912_irq_init(struct tps65912 *tps65912, int irq,
 157                            struct tps65912_platform_data *pdata)
 158{
 159        int ret, cur_irq;
 160        int flags = IRQF_ONESHOT;
 161        u8 reg;
 162
 163        if (!irq) {
 164                dev_warn(tps65912->dev, "No interrupt support, no core IRQ\n");
 165                return 0;
 166        }
 167
 168        if (!pdata || !pdata->irq_base) {
 169                dev_warn(tps65912->dev, "No interrupt support, no IRQ base\n");
 170                return 0;
 171        }
 172
 173        /* Clear unattended interrupts */
 174        tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
 175        tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
 176        tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
 177        tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
 178        tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
 179        tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
 180        tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
 181        tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
 182
 183        /* Mask top level interrupts */
 184        tps65912->irq_mask = 0xFFFFFFFF;
 185
 186        mutex_init(&tps65912->irq_lock);
 187        tps65912->chip_irq = irq;
 188        tps65912->irq_base = pdata->irq_base;
 189
 190        tps65912->irq_num = TPS65912_NUM_IRQ;
 191
 192        /* Register with genirq */
 193        for (cur_irq = tps65912->irq_base;
 194             cur_irq < tps65912->irq_num + tps65912->irq_base;
 195             cur_irq++) {
 196                irq_set_chip_data(cur_irq, tps65912);
 197                irq_set_chip_and_handler(cur_irq, &tps65912_irq_chip,
 198                                         handle_edge_irq);
 199                irq_set_nested_thread(cur_irq, 1);
 200                irq_clear_status_flags(cur_irq, IRQ_NOREQUEST | IRQ_NOPROBE);
 201        }
 202
 203        ret = request_threaded_irq(irq, NULL, tps65912_irq, flags,
 204                                   "tps65912", tps65912);
 205
 206        irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
 207        if (ret != 0)
 208                dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret);
 209
 210        return ret;
 211}
 212
 213int tps65912_irq_exit(struct tps65912 *tps65912)
 214{
 215        free_irq(tps65912->chip_irq, tps65912);
 216        return 0;
 217}
 218