root/drivers/mfd/rc5t583-irq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rc5t583_irq_lock
  2. rc5t583_irq_unmask
  3. rc5t583_irq_mask
  4. rc5t583_irq_set_type
  5. rc5t583_irq_sync_unlock
  6. rc5t583_irq_set_wake
  7. rc5t583_irq
  8. rc5t583_irq_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Interrupt driver for RICOH583 power management chip.
   4  *
   5  * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
   6  * Author: Laxman dewangan <ldewangan@nvidia.com>
   7  *
   8  * based on code
   9  *      Copyright (C) 2011 RICOH COMPANY,LTD
  10  */
  11 #include <linux/interrupt.h>
  12 #include <linux/irq.h>
  13 #include <linux/i2c.h>
  14 #include <linux/mfd/rc5t583.h>
  15 
  16 enum int_type {
  17         SYS_INT  = 0x1,
  18         DCDC_INT = 0x2,
  19         RTC_INT  = 0x4,
  20         ADC_INT  = 0x8,
  21         GPIO_INT = 0x10,
  22 };
  23 
  24 static int gpedge_add[] = {
  25         RC5T583_GPIO_GPEDGE2,
  26         RC5T583_GPIO_GPEDGE2
  27 };
  28 
  29 static int irq_en_add[] = {
  30         RC5T583_INT_EN_SYS1,
  31         RC5T583_INT_EN_SYS2,
  32         RC5T583_INT_EN_DCDC,
  33         RC5T583_INT_EN_RTC,
  34         RC5T583_INT_EN_ADC1,
  35         RC5T583_INT_EN_ADC2,
  36         RC5T583_INT_EN_ADC3,
  37         RC5T583_GPIO_EN_INT
  38 };
  39 
  40 static int irq_mon_add[] = {
  41         RC5T583_INT_MON_SYS1,
  42         RC5T583_INT_MON_SYS2,
  43         RC5T583_INT_MON_DCDC,
  44         RC5T583_INT_MON_RTC,
  45         RC5T583_INT_IR_ADCL,
  46         RC5T583_INT_IR_ADCH,
  47         RC5T583_INT_IR_ADCEND,
  48         RC5T583_INT_IR_GPIOF,
  49         RC5T583_INT_IR_GPIOR
  50 };
  51 
  52 static int irq_clr_add[] = {
  53         RC5T583_INT_IR_SYS1,
  54         RC5T583_INT_IR_SYS2,
  55         RC5T583_INT_IR_DCDC,
  56         RC5T583_INT_IR_RTC,
  57         RC5T583_INT_IR_ADCL,
  58         RC5T583_INT_IR_ADCH,
  59         RC5T583_INT_IR_ADCEND,
  60         RC5T583_INT_IR_GPIOF,
  61         RC5T583_INT_IR_GPIOR
  62 };
  63 
  64 static int main_int_type[] = {
  65         SYS_INT,
  66         SYS_INT,
  67         DCDC_INT,
  68         RTC_INT,
  69         ADC_INT,
  70         ADC_INT,
  71         ADC_INT,
  72         GPIO_INT,
  73         GPIO_INT,
  74 };
  75 
  76 struct rc5t583_irq_data {
  77         u8      int_type;
  78         u8      master_bit;
  79         u8      int_en_bit;
  80         u8      mask_reg_index;
  81         int     grp_index;
  82 };
  83 
  84 #define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
  85                         _int_bit, _mask_ind)            \
  86         {                                               \
  87                 .int_type       = _int_type,            \
  88                 .master_bit     = _master_bit,          \
  89                 .grp_index      = _grp_index,           \
  90                 .int_en_bit     = _int_bit,             \
  91                 .mask_reg_index = _mask_ind,            \
  92         }
  93 
  94 static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
  95         [RC5T583_IRQ_ONKEY]             = RC5T583_IRQ(SYS_INT,  0, 0, 0, 0),
  96         [RC5T583_IRQ_ACOK]              = RC5T583_IRQ(SYS_INT,  0, 1, 1, 0),
  97         [RC5T583_IRQ_LIDOPEN]           = RC5T583_IRQ(SYS_INT,  0, 2, 2, 0),
  98         [RC5T583_IRQ_PREOT]             = RC5T583_IRQ(SYS_INT,  0, 3, 3, 0),
  99         [RC5T583_IRQ_CLKSTP]            = RC5T583_IRQ(SYS_INT,  0, 4, 4, 0),
 100         [RC5T583_IRQ_ONKEY_OFF]         = RC5T583_IRQ(SYS_INT,  0, 5, 5, 0),
 101         [RC5T583_IRQ_WD]                = RC5T583_IRQ(SYS_INT,  0, 7, 7, 0),
 102         [RC5T583_IRQ_EN_PWRREQ1]        = RC5T583_IRQ(SYS_INT,  0, 8, 0, 1),
 103         [RC5T583_IRQ_EN_PWRREQ2]        = RC5T583_IRQ(SYS_INT,  0, 9, 1, 1),
 104         [RC5T583_IRQ_PRE_VINDET]        = RC5T583_IRQ(SYS_INT,  0, 10, 2, 1),
 105 
 106         [RC5T583_IRQ_DC0LIM]            = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
 107         [RC5T583_IRQ_DC1LIM]            = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
 108         [RC5T583_IRQ_DC2LIM]            = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
 109         [RC5T583_IRQ_DC3LIM]            = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
 110 
 111         [RC5T583_IRQ_CTC]               = RC5T583_IRQ(RTC_INT,  2, 0, 0, 3),
 112         [RC5T583_IRQ_YALE]              = RC5T583_IRQ(RTC_INT,  2, 5, 5, 3),
 113         [RC5T583_IRQ_DALE]              = RC5T583_IRQ(RTC_INT,  2, 6, 6, 3),
 114         [RC5T583_IRQ_WALE]              = RC5T583_IRQ(RTC_INT,  2, 7, 7, 3),
 115 
 116         [RC5T583_IRQ_AIN1L]             = RC5T583_IRQ(ADC_INT,  3, 0, 0, 4),
 117         [RC5T583_IRQ_AIN2L]             = RC5T583_IRQ(ADC_INT,  3, 1, 1, 4),
 118         [RC5T583_IRQ_AIN3L]             = RC5T583_IRQ(ADC_INT,  3, 2, 2, 4),
 119         [RC5T583_IRQ_VBATL]             = RC5T583_IRQ(ADC_INT,  3, 3, 3, 4),
 120         [RC5T583_IRQ_VIN3L]             = RC5T583_IRQ(ADC_INT,  3, 4, 4, 4),
 121         [RC5T583_IRQ_VIN8L]             = RC5T583_IRQ(ADC_INT,  3, 5, 5, 4),
 122         [RC5T583_IRQ_AIN1H]             = RC5T583_IRQ(ADC_INT,  3, 6, 0, 5),
 123         [RC5T583_IRQ_AIN2H]             = RC5T583_IRQ(ADC_INT,  3, 7, 1, 5),
 124         [RC5T583_IRQ_AIN3H]             = RC5T583_IRQ(ADC_INT,  3, 8, 2, 5),
 125         [RC5T583_IRQ_VBATH]             = RC5T583_IRQ(ADC_INT,  3, 9, 3, 5),
 126         [RC5T583_IRQ_VIN3H]             = RC5T583_IRQ(ADC_INT,  3, 10, 4, 5),
 127         [RC5T583_IRQ_VIN8H]             = RC5T583_IRQ(ADC_INT,  3, 11, 5, 5),
 128         [RC5T583_IRQ_ADCEND]            = RC5T583_IRQ(ADC_INT,  3, 12, 0, 6),
 129 
 130         [RC5T583_IRQ_GPIO0]             = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
 131         [RC5T583_IRQ_GPIO1]             = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
 132         [RC5T583_IRQ_GPIO2]             = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
 133         [RC5T583_IRQ_GPIO3]             = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
 134         [RC5T583_IRQ_GPIO4]             = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
 135         [RC5T583_IRQ_GPIO5]             = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
 136         [RC5T583_IRQ_GPIO6]             = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
 137         [RC5T583_IRQ_GPIO7]             = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
 138 };
 139 
 140 static void rc5t583_irq_lock(struct irq_data *irq_data)
 141 {
 142         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 143         mutex_lock(&rc5t583->irq_lock);
 144 }
 145 
 146 static void rc5t583_irq_unmask(struct irq_data *irq_data)
 147 {
 148         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 149         unsigned int __irq = irq_data->irq - rc5t583->irq_base;
 150         const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
 151 
 152         rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
 153         rc5t583->intc_inten_reg |= 1 << data->master_bit;
 154         rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
 155 }
 156 
 157 static void rc5t583_irq_mask(struct irq_data *irq_data)
 158 {
 159         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 160         unsigned int __irq = irq_data->irq - rc5t583->irq_base;
 161         const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
 162 
 163         rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
 164         if (!rc5t583->group_irq_en[data->grp_index])
 165                 rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
 166 
 167         rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
 168 }
 169 
 170 static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
 171 {
 172         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 173         unsigned int __irq = irq_data->irq - rc5t583->irq_base;
 174         const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
 175         int val = 0;
 176         int gpedge_index;
 177         int gpedge_bit_pos;
 178 
 179         /* Supporting only trigger level inetrrupt */
 180         if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
 181                 gpedge_index = data->int_en_bit / 4;
 182                 gpedge_bit_pos = data->int_en_bit % 4;
 183 
 184                 if (type & IRQ_TYPE_EDGE_FALLING)
 185                         val |= 0x2;
 186 
 187                 if (type & IRQ_TYPE_EDGE_RISING)
 188                         val |= 0x1;
 189 
 190                 rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
 191                 rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
 192                 rc5t583_irq_unmask(irq_data);
 193                 return 0;
 194         }
 195         return -EINVAL;
 196 }
 197 
 198 static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
 199 {
 200         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 201         int i;
 202         int ret;
 203 
 204         for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
 205                 ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
 206                                 rc5t583->gpedge_reg[i]);
 207                 if (ret < 0)
 208                         dev_warn(rc5t583->dev,
 209                                 "Error in writing reg 0x%02x error: %d\n",
 210                                 gpedge_add[i], ret);
 211         }
 212 
 213         for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
 214                 ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
 215                                         rc5t583->irq_en_reg[i]);
 216                 if (ret < 0)
 217                         dev_warn(rc5t583->dev,
 218                                 "Error in writing reg 0x%02x error: %d\n",
 219                                 irq_en_add[i], ret);
 220         }
 221 
 222         ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
 223                                 rc5t583->intc_inten_reg);
 224         if (ret < 0)
 225                 dev_warn(rc5t583->dev,
 226                         "Error in writing reg 0x%02x error: %d\n",
 227                         RC5T583_INTC_INTEN, ret);
 228 
 229         mutex_unlock(&rc5t583->irq_lock);
 230 }
 231 #ifdef CONFIG_PM_SLEEP
 232 static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
 233 {
 234         struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
 235         return irq_set_irq_wake(rc5t583->chip_irq, on);
 236 }
 237 #else
 238 #define rc5t583_irq_set_wake NULL
 239 #endif
 240 
 241 static irqreturn_t rc5t583_irq(int irq, void *data)
 242 {
 243         struct rc5t583 *rc5t583 = data;
 244         uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
 245         uint8_t master_int = 0;
 246         int i;
 247         int ret;
 248         unsigned int rtc_int_sts = 0;
 249 
 250         /* Clear the status */
 251         for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
 252                 int_sts[i] = 0;
 253 
 254         ret  = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
 255         if (ret < 0) {
 256                 dev_err(rc5t583->dev,
 257                         "Error in reading reg 0x%02x error: %d\n",
 258                         RC5T583_INTC_INTMON, ret);
 259                 return IRQ_HANDLED;
 260         }
 261 
 262         for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
 263                 if (!(master_int & main_int_type[i]))
 264                         continue;
 265 
 266                 ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
 267                 if (ret < 0) {
 268                         dev_warn(rc5t583->dev,
 269                                 "Error in reading reg 0x%02x error: %d\n",
 270                                 irq_mon_add[i], ret);
 271                         int_sts[i] = 0;
 272                         continue;
 273                 }
 274 
 275                 if (main_int_type[i] & RTC_INT) {
 276                         rtc_int_sts = 0;
 277                         if (int_sts[i] & 0x1)
 278                                 rtc_int_sts |= BIT(6);
 279                         if (int_sts[i] & 0x2)
 280                                 rtc_int_sts |= BIT(7);
 281                         if (int_sts[i] & 0x4)
 282                                 rtc_int_sts |= BIT(0);
 283                         if (int_sts[i] & 0x8)
 284                                 rtc_int_sts |= BIT(5);
 285                 }
 286 
 287                 ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
 288                                 ~int_sts[i]);
 289                 if (ret < 0)
 290                         dev_warn(rc5t583->dev,
 291                                 "Error in reading reg 0x%02x error: %d\n",
 292                                 irq_clr_add[i], ret);
 293 
 294                 if (main_int_type[i] & RTC_INT)
 295                         int_sts[i] = rtc_int_sts;
 296         }
 297 
 298         /* Merge gpio interrupts for rising and falling case*/
 299         int_sts[7] |= int_sts[8];
 300 
 301         /* Call interrupt handler if enabled */
 302         for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
 303                 const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
 304                 if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
 305                         (rc5t583->group_irq_en[data->master_bit] &
 306                                         (1 << data->grp_index)))
 307                         handle_nested_irq(rc5t583->irq_base + i);
 308         }
 309 
 310         return IRQ_HANDLED;
 311 }
 312 
 313 static struct irq_chip rc5t583_irq_chip = {
 314         .name = "rc5t583-irq",
 315         .irq_mask = rc5t583_irq_mask,
 316         .irq_unmask = rc5t583_irq_unmask,
 317         .irq_bus_lock = rc5t583_irq_lock,
 318         .irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
 319         .irq_set_type = rc5t583_irq_set_type,
 320         .irq_set_wake = rc5t583_irq_set_wake,
 321 };
 322 
 323 int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
 324 {
 325         int i, ret;
 326 
 327         if (!irq_base) {
 328                 dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
 329                 return -EINVAL;
 330         }
 331 
 332         mutex_init(&rc5t583->irq_lock);
 333 
 334         /* Initailize all int register to 0 */
 335         for (i = 0; i < RC5T583_MAX_INTERRUPT_EN_REGS; i++)  {
 336                 ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
 337                                 rc5t583->irq_en_reg[i]);
 338                 if (ret < 0)
 339                         dev_warn(rc5t583->dev,
 340                                 "Error in writing reg 0x%02x error: %d\n",
 341                                 irq_en_add[i], ret);
 342         }
 343 
 344         for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++)  {
 345                 ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
 346                                 rc5t583->gpedge_reg[i]);
 347                 if (ret < 0)
 348                         dev_warn(rc5t583->dev,
 349                                 "Error in writing reg 0x%02x error: %d\n",
 350                                 gpedge_add[i], ret);
 351         }
 352 
 353         ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
 354         if (ret < 0)
 355                 dev_warn(rc5t583->dev,
 356                         "Error in writing reg 0x%02x error: %d\n",
 357                         RC5T583_INTC_INTEN, ret);
 358 
 359         /* Clear all interrupts in case they woke up active. */
 360         for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)  {
 361                 ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
 362                 if (ret < 0)
 363                         dev_warn(rc5t583->dev,
 364                                 "Error in writing reg 0x%02x error: %d\n",
 365                                 irq_clr_add[i], ret);
 366         }
 367 
 368         rc5t583->irq_base = irq_base;
 369         rc5t583->chip_irq = irq;
 370 
 371         for (i = 0; i < RC5T583_MAX_IRQS; i++) {
 372                 int __irq = i + rc5t583->irq_base;
 373                 irq_set_chip_data(__irq, rc5t583);
 374                 irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
 375                                          handle_simple_irq);
 376                 irq_set_nested_thread(__irq, 1);
 377                 irq_clear_status_flags(__irq, IRQ_NOREQUEST);
 378         }
 379 
 380         ret = devm_request_threaded_irq(rc5t583->dev, irq, NULL, rc5t583_irq,
 381                                         IRQF_ONESHOT, "rc5t583", rc5t583);
 382         if (ret < 0)
 383                 dev_err(rc5t583->dev,
 384                         "Error in registering interrupt error: %d\n", ret);
 385         return ret;
 386 }

/* [<][>][^][v][top][bottom][index][help] */