1e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/* 2e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * twl6030-irq.c - TWL6030 irq support 3e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 4e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Copyright (C) 2005-2009 Texas Instruments, Inc. 5e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 6e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Modifications to defer interrupt handling to a kernel thread: 7e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Copyright (C) 2006 MontaVista Software, Inc. 8e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 9e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Based on tlv320aic23.c: 10e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> 11e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 12e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Code cleanup and modifications to IRQ handler. 13e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * by syed khasim <x0khasim@ti.com> 14e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 15e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * TWL6030 specific code and IRQ handling changes by 16e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com> 17e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Balaji T K <balajitk@ti.com> 18e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 19e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * This program is free software; you can redistribute it and/or modify 20e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * it under the terms of the GNU General Public License as published by 21e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * the Free Software Foundation; either version 2 of the License, or 22e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * (at your option) any later version. 23e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 24e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * This program is distributed in the hope that it will be useful, 25e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * but WITHOUT ANY WARRANTY; without even the implied warranty of 26e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * GNU General Public License for more details. 28e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 29e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * You should have received a copy of the GNU General Public License 30e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * along with this program; if not, write to the Free Software 31e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 33e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 34e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#include <linux/init.h> 355d4a357d8f5e07868a90071f328fec73036e9628Paul Gortmaker#include <linux/export.h> 36e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#include <linux/interrupt.h> 37e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#include <linux/irq.h> 38e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#include <linux/kthread.h> 39e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#include <linux/i2c/twl.h> 4072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala#include <linux/platform_device.h> 41ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor#include <linux/suspend.h> 42e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 43b0b4a7c28ebee0763cae90d470cfff501a83be37G, Manjunath Kondaiah#include "twl-core.h" 44b0b4a7c28ebee0763cae90d470cfff501a83be37G, Manjunath Kondaiah 45e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/* 46e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * TWL6030 (unlike its predecessors, which had two level interrupt handling) 47e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C. 48e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * It exposes status bits saying who has raised an interrupt. There are 49e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * three mask registers that corresponds to these status registers, that 50e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * enables/disables these interrupts. 51e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 52e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * We set up IRQs starting at a platform-specified base. An interrupt map table, 53e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * specifies mapping between interrupt number and the associated module. 54e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * 55e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 56e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 57e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic int twl6030_interrupt_mapping[24] = { 58e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K PWR_INTR_OFFSET, /* Bit 0 PWRON */ 59e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K PWR_INTR_OFFSET, /* Bit 1 RPWRON */ 60e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */ 61e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ 62e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ 63e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ 64e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ 65e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 7 VMMC_SHORT */ 66e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 67e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K SMPSLDO_INTR_OFFSET, /* Bit 8 VUSIM_SHORT */ 68e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ 69e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ 70e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ 71e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K RSV_INTR_OFFSET, /* Bit 12 Reserved */ 72e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K MADC_INTR_OFFSET, /* Bit 13 GPADC_RT_EOC */ 73e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K MADC_INTR_OFFSET, /* Bit 14 GPADC_SW_EOC */ 74e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ 75e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 76e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ 77e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ 78e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K USBOTG_INTR_OFFSET, /* Bit 18 ID */ 7977b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ 80e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ 816523b148b44be38d89c2ee9865d34da30d9f5f1cGraeme Gregory CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ 826523b148b44be38d89c2ee9865d34da30d9f5f1cGraeme Gregory CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ 83e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K RSV_INTR_OFFSET, /* Bit 23 Reserved */ 84e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K}; 85e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/*----------------------------------------------------------------------*/ 86e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 87e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic unsigned twl6030_irq_base; 88ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynorstatic int twl_irq; 89ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynorstatic bool twl_irq_wake_enabled; 90e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 91e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic struct completion irq_event; 92ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynorstatic atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); 93ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 94ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynorstatic int twl6030_irq_pm_notifier(struct notifier_block *notifier, 95ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor unsigned long pm_event, void *unused) 96ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor{ 97ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor int chained_wakeups; 98ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 99ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor switch (pm_event) { 100ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor case PM_SUSPEND_PREPARE: 101ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor chained_wakeups = atomic_read(&twl6030_wakeirqs); 102ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 103ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor if (chained_wakeups && !twl_irq_wake_enabled) { 104ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor if (enable_irq_wake(twl_irq)) 105ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor pr_err("twl6030 IRQ wake enable failed\n"); 106ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor else 107ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor twl_irq_wake_enabled = true; 108ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor } else if (!chained_wakeups && twl_irq_wake_enabled) { 109ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor disable_irq_wake(twl_irq); 110ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor twl_irq_wake_enabled = false; 111ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor } 112ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 113782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor disable_irq(twl_irq); 114ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor break; 115782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor 116782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor case PM_POST_SUSPEND: 117782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor enable_irq(twl_irq); 118782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor break; 119782baa20b201100e14ce065bb7b890169e7a5d3cTodd Poynor 120ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor default: 121ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor break; 122ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor } 123ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 124ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor return NOTIFY_DONE; 125ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor} 126ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 127ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynorstatic struct notifier_block twl6030_irq_pm_notifier_block = { 128ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor .notifier_call = twl6030_irq_pm_notifier, 129ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor}; 130e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 131e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/* 132e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * This thread processes interrupts reported by the Primary Interrupt Handler. 133e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 134e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic int twl6030_irq_thread(void *data) 135e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 136e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K long irq = (long)data; 137e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K static unsigned i2c_errors; 138e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K static const unsigned max_i2c_errors = 100; 139e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int ret; 140e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 141e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K while (!kthread_should_stop()) { 142e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int i; 143e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K union { 144e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K u8 bytes[4]; 145e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K u32 int_sts; 146e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } sts; 147e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 148e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* Wait for IRQ, then read PIH irq status (also blocking) */ 149e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K wait_for_completion_interruptible(&irq_event); 150e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 151e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* read INT_STS_A, B and C in one shot using a burst read */ 152e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, 153e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A, 3); 154e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (ret) { 155e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K pr_warning("twl6030: I2C error %d reading PIH ISR\n", 156e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret); 157e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (++i2c_errors >= max_i2c_errors) { 158e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K printk(KERN_ERR "Maximum I2C error count" 159e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K " exceeded. Terminating %s.\n", 160e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K __func__); 161e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K break; 162e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 163e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K complete(&irq_event); 164e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K continue; 165e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 166e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 167e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 168e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 169e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K sts.bytes[3] = 0; /* Only 24 bits are valid*/ 170e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 17177b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK /* 17277b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK * Since VBUS status bit is not reliable for VBUS disconnect 17377b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK * use CHARGER VBUS detection status bit instead. 17477b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK */ 17577b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK if (sts.bytes[2] & 0x10) 17677b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK sts.bytes[2] |= 0x08; 17777b1d3fa88dcb9d6e885926f972c421e4069b849Hema HK 178e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { 179e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K local_irq_disable(); 180e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (sts.int_sts & 0x1) { 181e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int module_irq = twl6030_irq_base + 182e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K twl6030_interrupt_mapping[i]; 183c22435a307e00b8ae947b79a8c0d94ab0bef404cThomas Gleixner generic_handle_irq(module_irq); 184e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 185e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 186e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K local_irq_enable(); 187e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 188e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, sts.bytes, 189e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A */ 190e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (ret) 191e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K pr_warning("twl6030: I2C error in clearing PIH ISR\n"); 192e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 193e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K enable_irq(irq); 194e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 195e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 196e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return 0; 197e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 198e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 199e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/* 200e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. 201e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * This is a chained interrupt, so there is no desc->action method for it. 202e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * Now we need to query the interrupt controller in the twl6030 to determine 203e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * which module is generating the interrupt request. However, we can't do i2c 204e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * transactions in interrupt context, so we must defer that work to a kernel 205e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * thread. All we do here is acknowledge and mask the interrupt and wakeup 206e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * the kernel thread. 207e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 208e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic irqreturn_t handle_twl6030_pih(int irq, void *devid) 209e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 210e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K disable_irq_nosync(irq); 211e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K complete(devid); 212e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return IRQ_HANDLED; 213e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 214e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 215e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/*----------------------------------------------------------------------*/ 216e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 217e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic inline void activate_irq(int irq) 218e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 219e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#ifdef CONFIG_ARM 220e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* ARM requires an extra step to clear IRQ_NOREQUEST, which it 221e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. 222e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 223e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K set_irq_flags(irq, IRQF_VALID); 224e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#else 225e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* same effect on other architectures */ 226d5bb122165981aed327845c32a9916d1b8ae0e4bThomas Gleixner irq_set_noprobe(irq); 227e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K#endif 228e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 229e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 23049dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkarint twl6030_irq_set_wake(struct irq_data *d, unsigned int on) 23149dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar{ 232ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor if (on) 233ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor atomic_inc(&twl6030_wakeirqs); 234ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor else 235ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor atomic_dec(&twl6030_wakeirqs); 23649dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar 237ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor return 0; 23849dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar} 23949dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar 240e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/*----------------------------------------------------------------------*/ 241e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 242e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kstatic unsigned twl6030_irq_next; 243e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 244e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K/*----------------------------------------------------------------------*/ 245e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kint twl6030_interrupt_unmask(u8 bit_mask, u8 offset) 246e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 247e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int ret; 248e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K u8 unmask_value; 249e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &unmask_value, 250e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A + offset); 251e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K unmask_value &= (~(bit_mask)); 252e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, unmask_value, 253e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A + offset); /* unmask INT_MSK_A/B/C */ 254e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return ret; 255e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 256e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T KEXPORT_SYMBOL(twl6030_interrupt_unmask); 257e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 258e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kint twl6030_interrupt_mask(u8 bit_mask, u8 offset) 259e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 260e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int ret; 261e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K u8 mask_value; 262e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_read_u8(TWL_MODULE_PIH, &mask_value, 263e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A + offset); 264e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K mask_value |= (bit_mask); 265e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret |= twl_i2c_write_u8(TWL_MODULE_PIH, mask_value, 266e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A + offset); /* mask INT_MSK_A/B/C */ 267e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return ret; 268e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 269e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T KEXPORT_SYMBOL(twl6030_interrupt_mask); 270e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 27172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyalaint twl6030_mmc_card_detect_config(void) 27272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala{ 27372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala int ret; 27472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala u8 reg_val = 0; 27572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala 27672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala /* Unmasking the Card detect Interrupt line for MMC1 from Phoenix */ 27772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 27872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala REG_INT_MSK_LINE_B); 27972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, 28072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala REG_INT_MSK_STS_B); 28172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala /* 28225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Initially Configuring MMC_CTRL for receiving interrupts & 28372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala * Card status on TWL6030 for MMC1 28472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala */ 28572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); 28672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (ret < 0) { 28772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala pr_err("twl6030: Failed to read MMCCTRL, error %d\n", ret); 28872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 28972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala } 29072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala reg_val &= ~VMMC_AUTO_OFF; 29172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala reg_val |= SW_FC; 29272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, TWL6030_MMCCTRL); 29372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (ret < 0) { 29472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala pr_err("twl6030: Failed to write MMCCTRL, error %d\n", ret); 29572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 29672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala } 29772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala 29872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala /* Configuring PullUp-PullDown register */ 29972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, 30072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala TWL6030_CFG_INPUT_PUPD3); 30172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (ret < 0) { 30272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala pr_err("twl6030: Failed to read CFG_INPUT_PUPD3, error %d\n", 30372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret); 30472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 30572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala } 30672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala reg_val &= ~(MMC_PU | MMC_PD); 30772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, reg_val, 30872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala TWL6030_CFG_INPUT_PUPD3); 30972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (ret < 0) { 31072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala pr_err("twl6030: Failed to write CFG_INPUT_PUPD3, error %d\n", 31172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret); 31272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 31372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala } 31472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return 0; 31572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala} 31672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyalaEXPORT_SYMBOL(twl6030_mmc_card_detect_config); 31772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala 31872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyalaint twl6030_mmc_card_detect(struct device *dev, int slot) 31972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala{ 32072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala int ret = -EIO; 32172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala u8 read_reg = 0; 32272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala struct platform_device *pdev = to_platform_device(dev); 32372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala 32472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (pdev->id) { 32572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala /* TWL6030 provide's Card detect support for 32672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala * only MMC1 controller. 32772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala */ 32825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi pr_err("Unknown MMC controller %d in %s\n", pdev->id, __func__); 32972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 33072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala } 33172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala /* 33272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala * BIT0 of MMC_CTRL on TWL6030 provides card status for MMC1 33372f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala * 0 - Card not present ,1 - Card present 33472f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala */ 33572f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, &read_reg, 33672f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala TWL6030_MMCCTRL); 33772f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala if (ret >= 0) 33872f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala ret = read_reg & STS_MMC; 33972f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala return ret; 34072f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala} 34172f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyalaEXPORT_SYMBOL(twl6030_mmc_card_detect); 34272f2e2c763edc41f8eead042b6ff933acb0378e2kishore kadiyala 343e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kint twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) 344e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 345e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 346e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int status = 0; 347e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int i; 348e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K struct task_struct *task; 349e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K int ret; 350e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K u8 mask[4]; 351e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 352e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K static struct irq_chip twl6030_irq_chip; 353e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K mask[1] = 0xFF; 354e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K mask[2] = 0xFF; 355e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K mask[3] = 0xFF; 356e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 357e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */ 358e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 359e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */ 360e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0], 361e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */ 362e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 363e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K twl6030_irq_base = irq_base; 364e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 365e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* install an irq handler for each of the modules; 366e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K * clone dummy irq_chip since PIH can't *do* anything 367e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K */ 368e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K twl6030_irq_chip = dummy_irq_chip; 369e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K twl6030_irq_chip.name = "twl6030"; 370c45c685c1a582e27787b5aa85844f2ee6986018cLennert Buytenhek twl6030_irq_chip.irq_set_type = NULL; 37149dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; 372e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 373e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K for (i = irq_base; i < irq_end; i++) { 374d5bb122165981aed327845c32a9916d1b8ae0e4bThomas Gleixner irq_set_chip_and_handler(i, &twl6030_irq_chip, 375d5bb122165981aed327845c32a9916d1b8ae0e4bThomas Gleixner handle_simple_irq); 37649dcd070d0718a8b8db344d7b3d5e278362ecd86Santosh Shilimkar irq_set_chip_data(i, (void *)irq_num); 377e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K activate_irq(i); 378e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 379e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 380e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K twl6030_irq_next = i; 381e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH", 382e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K irq_num, irq_base, twl6030_irq_next - 1); 383e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 384e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K /* install an irq handler to demultiplex the TWL6030 interrupt */ 385e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K init_completion(&irq_event); 386e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 387f742b96e42f886a415633a1fed0db2bb09d2baa3Yong Zhang status = request_irq(irq_num, handle_twl6030_pih, 0, 388e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K "TWL6030-PIH", &irq_event); 389e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (status < 0) { 390e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status); 391e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K goto fail_irq; 392e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 393862de70c12bb6227943e155251c75e7fa4558068Axel Lin 394862de70c12bb6227943e155251c75e7fa4558068Axel Lin task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); 395862de70c12bb6227943e155251c75e7fa4558068Axel Lin if (IS_ERR(task)) { 396862de70c12bb6227943e155251c75e7fa4558068Axel Lin pr_err("twl6030: could not create irq %d thread!\n", irq_num); 397862de70c12bb6227943e155251c75e7fa4558068Axel Lin status = PTR_ERR(task); 398862de70c12bb6227943e155251c75e7fa4558068Axel Lin goto fail_kthread; 399862de70c12bb6227943e155251c75e7fa4558068Axel Lin } 400ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor 401ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor twl_irq = irq_num; 402ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor register_pm_notifier(&twl6030_irq_pm_notifier_block); 403e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return status; 404e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 405e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kfail_kthread: 406862de70c12bb6227943e155251c75e7fa4558068Axel Lin free_irq(irq_num, &irq_event); 407862de70c12bb6227943e155251c75e7fa4558068Axel Lin 408862de70c12bb6227943e155251c75e7fa4558068Axel Linfail_irq: 409e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K for (i = irq_base; i < irq_end; i++) 410d5bb122165981aed327845c32a9916d1b8ae0e4bThomas Gleixner irq_set_chip_and_handler(i, NULL, NULL); 411e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return status; 412e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 413e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 414e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T Kint twl6030_exit_irq(void) 415e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K{ 416ab2b9260df67e29d5bd69d989f2f84f8c2ed4238Todd Poynor unregister_pm_notifier(&twl6030_irq_pm_notifier_block); 417e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 418e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K if (twl6030_irq_base) { 419e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K pr_err("twl6030: can't yet clean up IRQs?\n"); 420e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return -ENOSYS; 421e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K } 422e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K return 0; 423e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K} 424e8deb28ca8e221de0239eafb3c3d431d8854278eBalaji T K 425