linux/drivers/mfd/max8998-irq.c
<<
>>
Prefs
   1/*
   2 * Interrupt controller support for MAX8998
   3 *
   4 * Copyright (C) 2010 Samsung Electronics Co.Ltd
   5 * Author: Joonyoung Shim <jy0922.shim@samsung.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 */
  13
  14#include <linux/device.h>
  15#include <linux/interrupt.h>
  16#include <linux/irq.h>
  17#include <linux/mfd/max8998-private.h>
  18
  19struct max8998_irq_data {
  20        int reg;
  21        int mask;
  22};
  23
  24static struct max8998_irq_data max8998_irqs[] = {
  25        [MAX8998_IRQ_DCINF] = {
  26                .reg = 1,
  27                .mask = MAX8998_IRQ_DCINF_MASK,
  28        },
  29        [MAX8998_IRQ_DCINR] = {
  30                .reg = 1,
  31                .mask = MAX8998_IRQ_DCINR_MASK,
  32        },
  33        [MAX8998_IRQ_JIGF] = {
  34                .reg = 1,
  35                .mask = MAX8998_IRQ_JIGF_MASK,
  36        },
  37        [MAX8998_IRQ_JIGR] = {
  38                .reg = 1,
  39                .mask = MAX8998_IRQ_JIGR_MASK,
  40        },
  41        [MAX8998_IRQ_PWRONF] = {
  42                .reg = 1,
  43                .mask = MAX8998_IRQ_PWRONF_MASK,
  44        },
  45        [MAX8998_IRQ_PWRONR] = {
  46                .reg = 1,
  47                .mask = MAX8998_IRQ_PWRONR_MASK,
  48        },
  49        [MAX8998_IRQ_WTSREVNT] = {
  50                .reg = 2,
  51                .mask = MAX8998_IRQ_WTSREVNT_MASK,
  52        },
  53        [MAX8998_IRQ_SMPLEVNT] = {
  54                .reg = 2,
  55                .mask = MAX8998_IRQ_SMPLEVNT_MASK,
  56        },
  57        [MAX8998_IRQ_ALARM1] = {
  58                .reg = 2,
  59                .mask = MAX8998_IRQ_ALARM1_MASK,
  60        },
  61        [MAX8998_IRQ_ALARM0] = {
  62                .reg = 2,
  63                .mask = MAX8998_IRQ_ALARM0_MASK,
  64        },
  65        [MAX8998_IRQ_ONKEY1S] = {
  66                .reg = 3,
  67                .mask = MAX8998_IRQ_ONKEY1S_MASK,
  68        },
  69        [MAX8998_IRQ_TOPOFFR] = {
  70                .reg = 3,
  71                .mask = MAX8998_IRQ_TOPOFFR_MASK,
  72        },
  73        [MAX8998_IRQ_DCINOVPR] = {
  74                .reg = 3,
  75                .mask = MAX8998_IRQ_DCINOVPR_MASK,
  76        },
  77        [MAX8998_IRQ_CHGRSTF] = {
  78                .reg = 3,
  79                .mask = MAX8998_IRQ_CHGRSTF_MASK,
  80        },
  81        [MAX8998_IRQ_DONER] = {
  82                .reg = 3,
  83                .mask = MAX8998_IRQ_DONER_MASK,
  84        },
  85        [MAX8998_IRQ_CHGFAULT] = {
  86                .reg = 3,
  87                .mask = MAX8998_IRQ_CHGFAULT_MASK,
  88        },
  89        [MAX8998_IRQ_LOBAT1] = {
  90                .reg = 4,
  91                .mask = MAX8998_IRQ_LOBAT1_MASK,
  92        },
  93        [MAX8998_IRQ_LOBAT2] = {
  94                .reg = 4,
  95                .mask = MAX8998_IRQ_LOBAT2_MASK,
  96        },
  97};
  98
  99static inline struct max8998_irq_data *
 100irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
 101{
 102        return &max8998_irqs[irq - max8998->irq_base];
 103}
 104
 105static void max8998_irq_lock(struct irq_data *data)
 106{
 107        struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
 108
 109        mutex_lock(&max8998->irqlock);
 110}
 111
 112static void max8998_irq_sync_unlock(struct irq_data *data)
 113{
 114        struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
 115        int i;
 116
 117        for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
 118                /*
 119                 * If there's been a change in the mask write it back
 120                 * to the hardware.
 121                 */
 122                if (max8998->irq_masks_cur[i] != max8998->irq_masks_cache[i]) {
 123                        max8998->irq_masks_cache[i] = max8998->irq_masks_cur[i];
 124                        max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i,
 125                                        max8998->irq_masks_cur[i]);
 126                }
 127        }
 128
 129        mutex_unlock(&max8998->irqlock);
 130}
 131
 132static void max8998_irq_unmask(struct irq_data *data)
 133{
 134        struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
 135        struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
 136                                                               data->irq);
 137
 138        max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 139}
 140
 141static void max8998_irq_mask(struct irq_data *data)
 142{
 143        struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
 144        struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
 145                                                               data->irq);
 146
 147        max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
 148}
 149
 150static struct irq_chip max8998_irq_chip = {
 151        .name = "max8998",
 152        .irq_bus_lock = max8998_irq_lock,
 153        .irq_bus_sync_unlock = max8998_irq_sync_unlock,
 154        .irq_mask = max8998_irq_mask,
 155        .irq_unmask = max8998_irq_unmask,
 156};
 157
 158static irqreturn_t max8998_irq_thread(int irq, void *data)
 159{
 160        struct max8998_dev *max8998 = data;
 161        u8 irq_reg[MAX8998_NUM_IRQ_REGS];
 162        int ret;
 163        int i;
 164
 165        ret = max8998_bulk_read(max8998->i2c, MAX8998_REG_IRQ1,
 166                        MAX8998_NUM_IRQ_REGS, irq_reg);
 167        if (ret < 0) {
 168                dev_err(max8998->dev, "Failed to read interrupt register: %d\n",
 169                                ret);
 170                return IRQ_NONE;
 171        }
 172
 173        /* Apply masking */
 174        for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++)
 175                irq_reg[i] &= ~max8998->irq_masks_cur[i];
 176
 177        /* Report */
 178        for (i = 0; i < MAX8998_IRQ_NR; i++) {
 179                if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
 180                        handle_nested_irq(max8998->irq_base + i);
 181        }
 182
 183        return IRQ_HANDLED;
 184}
 185
 186int max8998_irq_resume(struct max8998_dev *max8998)
 187{
 188        if (max8998->irq && max8998->irq_base)
 189                max8998_irq_thread(max8998->irq_base, max8998);
 190        return 0;
 191}
 192
 193int max8998_irq_init(struct max8998_dev *max8998)
 194{
 195        int i;
 196        int cur_irq;
 197        int ret;
 198
 199        if (!max8998->irq) {
 200                dev_warn(max8998->dev,
 201                         "No interrupt specified, no interrupts\n");
 202                max8998->irq_base = 0;
 203                return 0;
 204        }
 205
 206        if (!max8998->irq_base) {
 207                dev_err(max8998->dev,
 208                        "No interrupt base specified, no interrupts\n");
 209                return 0;
 210        }
 211
 212        mutex_init(&max8998->irqlock);
 213
 214        /* Mask the individual interrupt sources */
 215        for (i = 0; i < MAX8998_NUM_IRQ_REGS; i++) {
 216                max8998->irq_masks_cur[i] = 0xff;
 217                max8998->irq_masks_cache[i] = 0xff;
 218                max8998_write_reg(max8998->i2c, MAX8998_REG_IRQM1 + i, 0xff);
 219        }
 220
 221        max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
 222        max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
 223
 224        /* register with genirq */
 225        for (i = 0; i < MAX8998_IRQ_NR; i++) {
 226                cur_irq = i + max8998->irq_base;
 227                irq_set_chip_data(cur_irq, max8998);
 228                irq_set_chip_and_handler(cur_irq, &max8998_irq_chip,
 229                                         handle_edge_irq);
 230                irq_set_nested_thread(cur_irq, 1);
 231#ifdef CONFIG_ARM
 232                set_irq_flags(cur_irq, IRQF_VALID);
 233#else
 234                irq_set_noprobe(cur_irq);
 235#endif
 236        }
 237
 238        ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
 239                                   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 240                                   "max8998-irq", max8998);
 241        if (ret) {
 242                dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
 243                        max8998->irq, ret);
 244                return ret;
 245        }
 246
 247        if (!max8998->ono)
 248                return 0;
 249
 250        ret = request_threaded_irq(max8998->ono, NULL, max8998_irq_thread,
 251                                   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
 252                                   IRQF_ONESHOT, "max8998-ono", max8998);
 253        if (ret)
 254                dev_err(max8998->dev, "Failed to request IRQ %d: %d\n",
 255                        max8998->ono, ret);
 256
 257        return 0;
 258}
 259
 260void max8998_irq_exit(struct max8998_dev *max8998)
 261{
 262        if (max8998->ono)
 263                free_irq(max8998->ono, max8998);
 264
 265        if (max8998->irq)
 266                free_irq(max8998->irq, max8998);
 267}
 268
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.