lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* |
| 2 | * zx234290-irq.c -- Interrupt controller support for ZX234290 PMICs |
| 3 | * |
| 4 | * Copyright 2016 ZTE Inc. |
| 5 | * |
| 6 | * Author: yuxiang<yu.xiang5@zte.com.cn> |
| 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 | */ |
| 14 | |
| 15 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> |
| 17 | #include <linux/init.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/zx234290.h> |
| 24 | #include <mach/pcu.h> |
| 25 | #include <mach/gpio.h> |
| 26 | #include <linux/sched.h> |
| 27 | #include <linux/semaphore.h> |
| 28 | #include <linux/kthread.h> |
| 29 | |
| 30 | #define INT_LOW_LEVEL /* yuxiang */ |
| 31 | #define ZX234290_INT_DEBUG |
| 32 | #ifdef ZX234290_INT_DEBUG |
| 33 | unsigned long int_irq_times = 0; |
| 34 | unsigned long int_thread_times = 0; |
| 35 | #endif |
| 36 | struct semaphore zx234290_sem; |
| 37 | |
| 38 | #define ZX234290_WAKELOCK 1 |
| 39 | #ifdef ZX234290_WAKELOCK |
| 40 | #include <linux/wakelock.h> |
| 41 | static struct wake_lock zx234290_wake_lock; |
| 42 | #endif |
| 43 | |
| 44 | #ifdef ZX234290_PWR_FAUL_PROCESS |
| 45 | extern int zx234290_regulator_error_irq_request(struct zx234290 *zx234290); |
| 46 | #endif |
| 47 | |
| 48 | static inline int irq_to_zx234290_irq(struct zx234290 *zx234290, |
| 49 | int irq) |
| 50 | { |
| 51 | return irq - zx234290->irq_base; |
| 52 | } |
| 53 | |
| 54 | /* |
| 55 | * This is a threaded IRQ handler so can access I2C/SPI. Since the |
| 56 | * IRQ handler explicitly clears the IRQ it handles the IRQ line |
| 57 | * will be reasserted and the physical IRQ will be handled again if |
| 58 | * another interrupt is asserted while we run - in the normal course |
| 59 | * of events this is a rare occurrence so we save I2C/SPI reads. We're |
| 60 | * also assuming that it's rare to get lots of interrupts firing |
| 61 | * simultaneously so try to minimise I/O. |
| 62 | */ |
| 63 | static int zx234290_irq(void *irq_data) |
| 64 | { |
| 65 | struct zx234290 *zx234290 = irq_data; |
| 66 | u32 irq_sts; |
| 67 | u32 irq_mask; |
| 68 | u8 buck_sts=0, buck_mask=0; |
| 69 | u8 ldo_sts=0, ldo_mask=0; |
| 70 | u8 reg; |
| 71 | int i; |
| 72 | int irq = zx234290->chip_irq; |
| 73 | |
| 74 | const struct sched_param param = { |
| 75 | .sched_priority = 31, |
| 76 | }; |
| 77 | sched_setscheduler(current, SCHED_FIFO, ¶m); |
| 78 | |
| 79 | while (!kthread_should_stop()) { |
| 80 | down(&zx234290_sem); |
| 81 | #ifdef ZX234290_WAKELOCK |
| 82 | wake_lock(&zx234290_wake_lock); |
| 83 | #endif |
| 84 | |
| 85 | #ifdef ZX234290_INT_DEBUG |
| 86 | int_thread_times ++; |
| 87 | #endif |
| 88 | //printk(KERN_INFO "zx234290 irq handler:irq=%d.\n", irq); |
| 89 | |
| 90 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 91 | irq_sts = reg; |
| 92 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTB, 1, ®); |
| 93 | irq_sts |= reg << 8; |
| 94 | |
| 95 | // printk(KERN_INFO "zx234290 irq handler:irq=%d, INTR_A=0x%02x, INTR_B=0x%02x\n", irq, irq_sts&0xFF, irq_sts>>8); |
| 96 | |
| 97 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, ®); |
| 98 | irq_mask = reg; |
| 99 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, ®); |
| 100 | irq_mask |= reg << 8; |
| 101 | |
| 102 | irq_sts &= ~irq_mask; /* */ |
| 103 | |
| 104 | #ifdef ZX234290_PWR_FAUL_PROCESS |
| 105 | //++ |
| 106 | zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_FAULT_STATUS, 1, &buck_sts); |
| 107 | zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_FAULT_STATUS, 1, &ldo_sts); |
| 108 | zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, &buck_mask); |
| 109 | zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, &ldo_mask); |
| 110 | |
| 111 | buck_sts &= ~buck_mask; |
| 112 | ldo_sts &= ~ldo_mask; |
| 113 | |
| 114 | if(buck_sts ) |
| 115 | irq_sts |= (1 << ZX234290_INT_BUCK_FAUL); |
| 116 | else |
| 117 | irq_sts &= ~(1 << ZX234290_INT_BUCK_FAUL); |
| 118 | |
| 119 | if(ldo_sts ) |
| 120 | irq_sts |= (1 << ZX234290_INT_LDO_FAUL); |
| 121 | else |
| 122 | irq_sts &= ~(1 << ZX234290_INT_LDO_FAUL); |
| 123 | |
| 124 | // if(buck_sts || ldo_sts) |
| 125 | // printk(KERN_INFO "zx234290 irq handler:buck_sts=0x%02x, ldo_sts=0x%02x, irq_sts=0x%x\n", buck_sts, ldo_sts, irq_sts); |
| 126 | #endif |
| 127 | |
| 128 | if (!irq_sts) |
| 129 | { |
| 130 | |
| 131 | #ifdef ZX234290_WAKELOCK |
| 132 | wake_unlock(&zx234290_wake_lock); |
| 133 | #endif |
| 134 | |
| 135 | #ifdef INT_LOW_LEVEL |
| 136 | pcu_clr_irq_pending(irq); |
| 137 | enable_irq(irq);//yx |
| 138 | #endif |
| 139 | //return IRQ_NONE; |
| 140 | continue; |
| 141 | } |
| 142 | |
| 143 | for (i = 0; i < zx234290->irq_num; i++) { |
| 144 | if (!(irq_sts & (1 << i))) |
| 145 | continue; |
| 146 | |
| 147 | handle_nested_irq(zx234290->irq_base + i); |
| 148 | } |
| 149 | /*write bit7 to be 0, clear pmu INT*/ |
| 150 | //zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 151 | //reg &= ~(0x1<<7); |
| 152 | //zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 153 | #if 0 |
| 154 | /* Write the STS register back to clear IRQs we handled */ |
| 155 | reg = irq_sts & 0xFF; |
| 156 | irq_sts >>= 8; |
| 157 | if (reg) |
| 158 | zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 159 | reg = irq_sts & 0xFF; |
| 160 | irq_sts >>= 8; |
| 161 | if (reg) |
| 162 | zx234290->write(zx234290, ZX234290_REG_ADDR_INTB, 1, ®); |
| 163 | #endif |
| 164 | |
| 165 | #ifdef ZX234290_WAKELOCK |
| 166 | wake_unlock(&zx234290_wake_lock); |
| 167 | #endif |
| 168 | |
| 169 | |
| 170 | #ifdef INT_LOW_LEVEL |
| 171 | pcu_clr_irq_pending(irq); |
| 172 | enable_irq(irq);//yx |
| 173 | #endif |
| 174 | } |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | static void zx234290_irq_lock(struct irq_data *data) |
| 179 | { |
| 180 | struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data); |
| 181 | |
| 182 | mutex_lock(&zx234290->irq_lock); |
| 183 | } |
| 184 | |
| 185 | static void zx234290_irq_sync_unlock(struct irq_data *data) |
| 186 | { |
| 187 | struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data); |
| 188 | u32 reg_mask; |
| 189 | u8 reg, reg2; |
| 190 | |
| 191 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, ®); |
| 192 | reg_mask = reg; |
| 193 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, ®); |
| 194 | reg_mask |= reg << 8; |
| 195 | /* take ldo6 & ldo8 error as buck error */ |
| 196 | zx234290->read(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, ®); |
| 197 | if (reg) |
| 198 | reg_mask |= BIT(ZX234290_INT_BUCK_FAUL); |
| 199 | zx234290->read(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, ®); |
| 200 | if (reg) |
| 201 | reg_mask |= BIT(ZX234290_INT_LDO_FAUL); |
| 202 | |
| 203 | if (zx234290->irq_mask != reg_mask) { |
| 204 | reg = zx234290->irq_mask & 0xFC; |
| 205 | zx234290->write(zx234290, ZX234290_REG_ADDR_INTA_MASK, 1, ®); |
| 206 | |
| 207 | reg = zx234290->irq_mask >> 8 & 0xFF; |
| 208 | zx234290->write(zx234290, ZX234290_REG_ADDR_INTB_MASK, 1, ®); |
| 209 | |
| 210 | reg = (zx234290->irq_mask & BIT(ZX234290_INT_BUCK_FAUL)) ? 0xFF : 0; |
| 211 | zx234290->write(zx234290, ZX234290_REG_ADDR_BUCK_INT_MASK, 1, ®); |
| 212 | |
| 213 | reg = (zx234290->irq_mask & BIT(ZX234290_INT_LDO_FAUL)) ? 0xFF : 0; |
| 214 | zx234290->write(zx234290, ZX234290_REG_ADDR_LDO_INT_MASK, 1, ®); |
| 215 | } |
| 216 | |
| 217 | mutex_unlock(&zx234290->irq_lock); |
| 218 | } |
| 219 | |
| 220 | static void zx234290_irq_enable(struct irq_data *data) |
| 221 | { |
| 222 | struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data); |
| 223 | |
| 224 | zx234290->irq_mask &= ~(1 << irq_to_zx234290_irq(zx234290, data->irq)); |
| 225 | } |
| 226 | |
| 227 | static void zx234290_irq_disable(struct irq_data *data) |
| 228 | { |
| 229 | struct zx234290 *zx234290 = irq_data_get_irq_chip_data(data); |
| 230 | |
| 231 | zx234290->irq_mask |= (1 << irq_to_zx234290_irq(zx234290, data->irq)); |
| 232 | } |
| 233 | |
| 234 | static struct irq_chip zx234290_irq_chip = { |
| 235 | .name = "zx234290", |
| 236 | .irq_bus_lock = zx234290_irq_lock, |
| 237 | .irq_bus_sync_unlock = zx234290_irq_sync_unlock, |
| 238 | .irq_disable = zx234290_irq_disable, |
| 239 | .irq_enable = zx234290_irq_enable, |
| 240 | }; |
| 241 | static irqreturn_t irq_primary_handler(int irq, void *dev_id) |
| 242 | { |
| 243 | #ifdef INT_LOW_LEVEL |
| 244 | disable_irq_nosync(irq);//yx |
| 245 | #endif |
| 246 | //pcu_int_clear(PCU_EX0_INT); //xzg |
| 247 | pcu_clr_irq_pending(irq); |
| 248 | up(&zx234290_sem); |
| 249 | #ifdef ZX234290_INT_DEBUG |
| 250 | int_irq_times ++; |
| 251 | #endif |
| 252 | |
| 253 | //return IRQ_WAKE_THREAD; |
| 254 | return IRQ_HANDLED; |
| 255 | } |
| 256 | |
| 257 | int zx234290_irq_init(struct zx234290 *zx234290, int irq, |
| 258 | struct zx234290_board *pdata) |
| 259 | { |
| 260 | int ret, cur_irq; |
| 261 | /* int flags = IRQF_ONESHOT; */ |
| 262 | u8 reg; |
| 263 | |
| 264 | #ifdef ZX234290_WAKELOCK |
| 265 | wake_lock_init(&zx234290_wake_lock, WAKE_LOCK_SUSPEND, "zx234290"); |
| 266 | #endif |
| 267 | |
| 268 | if (!irq) { |
| 269 | dev_warn(zx234290->dev, "No interrupt support, no core IRQ\n"); |
| 270 | return 0; |
| 271 | } |
| 272 | |
| 273 | if (!pdata || !pdata->irq_base) { |
| 274 | dev_warn(zx234290->dev, "No interrupt support, no IRQ base\n"); |
| 275 | return 0; |
| 276 | } |
| 277 | |
| 278 | sema_init(&zx234290_sem, 0); |
| 279 | /* Clear unattended interrupts */ |
| 280 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 281 | //zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 282 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTB, 1, ®); |
| 283 | //zx234290->write(zx234290, ZX234290_REG_ADDR_INTB, 1, ®); |
| 284 | |
| 285 | /*write bit7 to be 0, clear pmu INT*/ |
| 286 | zx234290->read(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 287 | reg &= ~(0x1<<7); |
| 288 | zx234290->write(zx234290, ZX234290_REG_ADDR_INTA, 1, ®); |
| 289 | |
| 290 | /* Mask top level interrupts */ |
| 291 | zx234290->irq_mask = 0xFFFF; |
| 292 | |
| 293 | mutex_init(&zx234290->irq_lock); |
| 294 | zx234290->chip_irq = irq; /* irq */ |
| 295 | zx234290->irq_base = pdata->irq_base; /* irq_base 32+49 */ |
| 296 | |
| 297 | zx234290->irq_num = ZX234290_NUM_IRQ; |
| 298 | |
| 299 | /* Register with genirq */ |
| 300 | for (cur_irq = zx234290->irq_base; |
| 301 | cur_irq < zx234290->irq_num + zx234290->irq_base; |
| 302 | cur_irq++) { |
| 303 | irq_set_chip_data(cur_irq, zx234290); |
| 304 | irq_set_chip_and_handler(cur_irq, &zx234290_irq_chip, |
| 305 | handle_edge_irq); |
| 306 | irq_set_nested_thread(cur_irq, 1); |
| 307 | /* ARM needs us to explicitly flag the IRQ as valid |
| 308 | * and will set them noprobe when we do so. */ |
| 309 | #ifdef CONFIG_ARM |
| 310 | set_irq_flags(cur_irq, IRQF_VALID); |
| 311 | #else |
| 312 | irq_set_noprobe(cur_irq); |
| 313 | #endif |
| 314 | } |
| 315 | |
| 316 | #ifdef ZX234290_PWR_FAUL_PROCESS |
| 317 | zx234290_regulator_error_irq_request(zx234290); |
| 318 | #endif |
| 319 | //unsigned int gpio_num = irq_to_gpio(irq);//by yuxiang |
| 320 | //#define GPIO_PMU_INT ZX29_GPIO_50 |
| 321 | /* GPIO reuse*/ |
| 322 | zx29_gpio_config(pdata->irq_gpio_num, pdata->irq_gpio_func); |
| 323 | #ifdef INT_LOW_LEVEL |
| 324 | zx29_gpio_set_inttype(pdata->irq_gpio_num, IRQ_TYPE_LEVEL_LOW); |
| 325 | #else |
| 326 | zx29_gpio_set_inttype(pdata->irq_gpio_num, IRQ_TYPE_EDGE_FALLING); |
| 327 | #endif |
| 328 | zx29_gpio_pd_pu_set(pdata->irq_gpio_num, 0); |
| 329 | //pcu_int_clear(PCU_EX0_INT); //by yuxiang |
| 330 | pcu_clr_irq_pending(irq); |
| 331 | //irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);//by yuxiang |
| 332 | //ret = request_threaded_irq(irq, irq_primary_handler, zx234290_irq, IRQF_ONESHOT, |
| 333 | // "zx234290", zx234290); |
| 334 | //µÈµ½pmuËùÓÐÄÚ²¿ÖжÏ×¢²áºó£¬ÔÙʹÄÜpmuÖÐ¶Ï |
| 335 | /* irq_set_status_flags(irq, IRQ_NOAUTOEN); */ |
| 336 | ret = request_irq(irq, irq_primary_handler, IRQF_NO_THREAD, |
| 337 | "zx234290", zx234290); |
| 338 | if (ret != 0) |
| 339 | dev_err(zx234290->dev, "Failed to request IRQ: %d\n", ret); |
| 340 | #ifndef CONFIG_ARCH_ZX297520V3_CAP |
| 341 | irq_set_irq_wake(irq, 1); |
| 342 | #endif |
| 343 | kthread_run(zx234290_irq, zx234290, "irq/%d-%s", irq, "zx234290"); |
| 344 | return ret; |
| 345 | } |
| 346 | |
| 347 | int zx234290_irq_exit(struct zx234290 *zx234290) |
| 348 | { |
| 349 | free_irq(zx234290->chip_irq, zx234290); |
| 350 | |
| 351 | #ifdef ZX234290_WAKELOCK |
| 352 | wake_lock_destroy(&zx234290_wake_lock); |
| 353 | #endif |
| 354 | |
| 355 | return 0; |
| 356 | } |