Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tps65912: irq: add interrupt controller

This module controls the interrupt handling for the tps65912.
The interrupt sources can be the following:

- GPIO
- PWRON signal
- PWRHOLD signal
- Temperature detection

Signed-off-by: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Margarita Olaya and committed by
Samuel Ortiz
d49a0f3f 36e52873

+243 -1
+1 -1
drivers/mfd/Makefile
··· 36 36 obj-$(CONFIG_TPS6105X) += tps6105x.o 37 37 obj-$(CONFIG_TPS65010) += tps65010.o 38 38 obj-$(CONFIG_TPS6507X) += tps6507x.o 39 - tps65912-objs := tps65912-core.o 39 + tps65912-objs := tps65912-core.o tps65912-irq.o 40 40 obj-$(CONFIG_MFD_TPS65912) += tps65912.o 41 41 obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o 42 42 obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
+13
drivers/mfd/tps65912-core.c
··· 124 124 int tps65912_device_init(struct tps65912 *tps65912) 125 125 { 126 126 struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data; 127 + struct tps65912_platform_data *init_data; 127 128 int ret, dcdc_avs, value; 129 + 130 + init_data = kzalloc(sizeof(struct tps65912_platform_data), GFP_KERNEL); 131 + if (init_data == NULL) 132 + return -ENOMEM; 133 + 134 + init_data->irq = pmic_plat_data->irq; 135 + init_data->irq_base = pmic_plat_data->irq; 128 136 129 137 mutex_init(&tps65912->io_mutex); 130 138 dev_set_drvdata(tps65912->dev, tps65912); ··· 153 145 if (ret < 0) 154 146 goto err; 155 147 148 + ret = tps65912_irq_init(tps65912, init_data->irq, init_data); 149 + if (ret < 0) 150 + goto err; 151 + 156 152 return ret; 157 153 158 154 err: 155 + kfree(init_data); 159 156 mfd_remove_devices(tps65912->dev); 160 157 kfree(tps65912); 161 158 return ret;
+224
drivers/mfd/tps65912-irq.c
··· 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/init.h> 19 + #include <linux/bug.h> 20 + #include <linux/device.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/irq.h> 23 + #include <linux/gpio.h> 24 + #include <linux/mfd/tps65912.h> 25 + 26 + static inline int irq_to_tps65912_irq(struct tps65912 *tps65912, 27 + int irq) 28 + { 29 + return irq - tps65912->irq_base; 30 + } 31 + 32 + /* 33 + * This is a threaded IRQ handler so can access I2C/SPI. Since the 34 + * IRQ handler explicitly clears the IRQ it handles the IRQ line 35 + * will be reasserted and the physical IRQ will be handled again if 36 + * another interrupt is asserted while we run - in the normal course 37 + * of events this is a rare occurrence so we save I2C/SPI reads. We're 38 + * also assuming that it's rare to get lots of interrupts firing 39 + * simultaneously so try to minimise I/O. 40 + */ 41 + static irqreturn_t tps65912_irq(int irq, void *irq_data) 42 + { 43 + struct tps65912 *tps65912 = irq_data; 44 + u32 irq_sts; 45 + u32 irq_mask; 46 + u8 reg; 47 + int i; 48 + 49 + 50 + tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg); 51 + irq_sts = reg; 52 + tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg); 53 + irq_sts |= reg << 8; 54 + tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg); 55 + irq_sts |= reg << 16; 56 + tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg); 57 + irq_sts |= reg << 24; 58 + 59 + tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg); 60 + irq_mask = reg; 61 + tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg); 62 + irq_mask |= reg << 8; 63 + tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg); 64 + irq_mask |= reg << 16; 65 + tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg); 66 + irq_mask |= reg << 24; 67 + 68 + irq_sts &= ~irq_mask; 69 + if (!irq_sts) 70 + return IRQ_NONE; 71 + 72 + for (i = 0; i < tps65912->irq_num; i++) { 73 + if (!(irq_sts & (1 << i))) 74 + continue; 75 + 76 + handle_nested_irq(tps65912->irq_base + i); 77 + } 78 + 79 + /* Write the STS register back to clear IRQs we handled */ 80 + reg = irq_sts & 0xFF; 81 + irq_sts >>= 8; 82 + if (reg) 83 + tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg); 84 + reg = irq_sts & 0xFF; 85 + irq_sts >>= 8; 86 + if (reg) 87 + tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg); 88 + reg = irq_sts & 0xFF; 89 + irq_sts >>= 8; 90 + if (reg) 91 + tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg); 92 + reg = irq_sts & 0xFF; 93 + if (reg) 94 + tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg); 95 + 96 + return IRQ_HANDLED; 97 + } 98 + 99 + static void tps65912_irq_lock(struct irq_data *data) 100 + { 101 + struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); 102 + 103 + mutex_lock(&tps65912->irq_lock); 104 + } 105 + 106 + static void tps65912_irq_sync_unlock(struct irq_data *data) 107 + { 108 + struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); 109 + u32 reg_mask; 110 + u8 reg; 111 + 112 + tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg); 113 + reg_mask = reg; 114 + tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg); 115 + reg_mask |= reg << 8; 116 + tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg); 117 + reg_mask |= reg << 16; 118 + tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg); 119 + reg_mask |= reg << 24; 120 + 121 + if (tps65912->irq_mask != reg_mask) { 122 + reg = tps65912->irq_mask & 0xFF; 123 + tps65912->write(tps65912, TPS65912_INT_MSK, 1, &reg); 124 + reg = tps65912->irq_mask >> 8 & 0xFF; 125 + tps65912->write(tps65912, TPS65912_INT_MSK2, 1, &reg); 126 + reg = tps65912->irq_mask >> 16 & 0xFF; 127 + tps65912->write(tps65912, TPS65912_INT_MSK3, 1, &reg); 128 + reg = tps65912->irq_mask >> 24 & 0xFF; 129 + tps65912->write(tps65912, TPS65912_INT_MSK4, 1, &reg); 130 + } 131 + 132 + mutex_unlock(&tps65912->irq_lock); 133 + } 134 + 135 + static void tps65912_irq_enable(struct irq_data *data) 136 + { 137 + struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); 138 + 139 + tps65912->irq_mask &= ~(1 << irq_to_tps65912_irq(tps65912, data->irq)); 140 + } 141 + 142 + static void tps65912_irq_disable(struct irq_data *data) 143 + { 144 + struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data); 145 + 146 + tps65912->irq_mask |= (1 << irq_to_tps65912_irq(tps65912, data->irq)); 147 + } 148 + 149 + static struct irq_chip tps65912_irq_chip = { 150 + .name = "tps65912", 151 + .irq_bus_lock = tps65912_irq_lock, 152 + .irq_bus_sync_unlock = tps65912_irq_sync_unlock, 153 + .irq_disable = tps65912_irq_disable, 154 + .irq_enable = tps65912_irq_enable, 155 + }; 156 + 157 + int tps65912_irq_init(struct tps65912 *tps65912, int irq, 158 + struct tps65912_platform_data *pdata) 159 + { 160 + int ret, cur_irq; 161 + int flags = IRQF_ONESHOT; 162 + u8 reg; 163 + 164 + if (!irq) { 165 + dev_warn(tps65912->dev, "No interrupt support, no core IRQ\n"); 166 + return 0; 167 + } 168 + 169 + if (!pdata || !pdata->irq_base) { 170 + dev_warn(tps65912->dev, "No interrupt support, no IRQ base\n"); 171 + return 0; 172 + } 173 + 174 + /* Clear unattended interrupts */ 175 + tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg); 176 + tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg); 177 + tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg); 178 + tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg); 179 + tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg); 180 + tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg); 181 + tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg); 182 + tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg); 183 + 184 + /* Mask top level interrupts */ 185 + tps65912->irq_mask = 0xFFFFFFFF; 186 + 187 + mutex_init(&tps65912->irq_lock); 188 + tps65912->chip_irq = irq; 189 + tps65912->irq_base = pdata->irq_base; 190 + 191 + tps65912->irq_num = TPS65912_NUM_IRQ; 192 + 193 + /* Register with genirq */ 194 + for (cur_irq = tps65912->irq_base; 195 + cur_irq < tps65912->irq_num + tps65912->irq_base; 196 + cur_irq++) { 197 + irq_set_chip_data(cur_irq, tps65912); 198 + irq_set_chip_and_handler(cur_irq, &tps65912_irq_chip, 199 + handle_edge_irq); 200 + irq_set_nested_thread(cur_irq, 1); 201 + /* ARM needs us to explicitly flag the IRQ as valid 202 + * and will set them noprobe when we do so. */ 203 + #ifdef CONFIG_ARM 204 + set_irq_flags(cur_irq, IRQF_VALID); 205 + #else 206 + irq_set_noprobe(cur_irq); 207 + #endif 208 + } 209 + 210 + ret = request_threaded_irq(irq, NULL, tps65912_irq, flags, 211 + "tps65912", tps65912); 212 + 213 + irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); 214 + if (ret != 0) 215 + dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret); 216 + 217 + return ret; 218 + } 219 + 220 + int tps65912_irq_exit(struct tps65912 *tps65912) 221 + { 222 + free_irq(tps65912->chip_irq, tps65912); 223 + return 0; 224 + }
+5
include/linux/mfd/tps65912.h
··· 273 273 int is_dcdc2_avs; 274 274 int is_dcdc3_avs; 275 275 int is_dcdc4_avs; 276 + int irq; 277 + int irq_base; 276 278 struct regulator_init_data *tps65912_pmic_init_data; 277 279 }; 278 280 ··· 308 306 }; 309 307 310 308 struct tps65912_platform_data { 309 + int irq; 311 310 int irq_base; 312 311 }; 313 312 ··· 320 317 int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val); 321 318 int tps65912_device_init(struct tps65912 *tps65912); 322 319 void tps65912_device_exit(struct tps65912 *tps65912); 320 + int tps65912_irq_init(struct tps65912 *tps65912, int irq, 321 + struct tps65912_platform_data *pdata); 323 322 324 323 #endif /* __LINUX_MFD_TPS65912_H */