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

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7-rc2 260 lines 6.7 kB view raw
1/* 2 * tps65910-irq.c -- TI TPS6591x 3 * 4 * Copyright 2010 Texas Instruments Inc. 5 * 6 * Author: Graeme Gregory <gg@slimlogic.co.uk> 7 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 * 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/irqdomain.h> 24#include <linux/gpio.h> 25#include <linux/mfd/tps65910.h> 26 27/* 28 * This is a threaded IRQ handler so can access I2C/SPI. Since all 29 * interrupts are clear on read the IRQ line will be reasserted and 30 * the physical IRQ will be handled again if another interrupt is 31 * asserted while we run - in the normal course of events this is a 32 * rare occurrence so we save I2C/SPI reads. We're also assuming that 33 * it's rare to get lots of interrupts firing simultaneously so try to 34 * minimise I/O. 35 */ 36static irqreturn_t tps65910_irq(int irq, void *irq_data) 37{ 38 struct tps65910 *tps65910 = irq_data; 39 unsigned int reg; 40 u32 irq_sts; 41 u32 irq_mask; 42 int i; 43 44 tps65910_reg_read(tps65910, TPS65910_INT_STS, &reg); 45 irq_sts = reg; 46 tps65910_reg_read(tps65910, TPS65910_INT_STS2, &reg); 47 irq_sts |= reg << 8; 48 switch (tps65910_chip_id(tps65910)) { 49 case TPS65911: 50 tps65910_reg_read(tps65910, TPS65910_INT_STS3, &reg); 51 irq_sts |= reg << 16; 52 } 53 54 tps65910_reg_read(tps65910, TPS65910_INT_MSK, &reg); 55 irq_mask = reg; 56 tps65910_reg_read(tps65910, TPS65910_INT_MSK2, &reg); 57 irq_mask |= reg << 8; 58 switch (tps65910_chip_id(tps65910)) { 59 case TPS65911: 60 tps65910_reg_read(tps65910, TPS65910_INT_MSK3, &reg); 61 irq_mask |= reg << 16; 62 } 63 64 irq_sts &= ~irq_mask; 65 66 if (!irq_sts) 67 return IRQ_NONE; 68 69 for (i = 0; i < tps65910->irq_num; i++) { 70 71 if (!(irq_sts & (1 << i))) 72 continue; 73 74 handle_nested_irq(irq_find_mapping(tps65910->domain, i)); 75 } 76 77 /* Write the STS register back to clear IRQs we handled */ 78 reg = irq_sts & 0xFF; 79 irq_sts >>= 8; 80 tps65910_reg_write(tps65910, TPS65910_INT_STS, reg); 81 reg = irq_sts & 0xFF; 82 tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg); 83 switch (tps65910_chip_id(tps65910)) { 84 case TPS65911: 85 reg = irq_sts >> 8; 86 tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg); 87 } 88 89 return IRQ_HANDLED; 90} 91 92static void tps65910_irq_lock(struct irq_data *data) 93{ 94 struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); 95 96 mutex_lock(&tps65910->irq_lock); 97} 98 99static void tps65910_irq_sync_unlock(struct irq_data *data) 100{ 101 struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); 102 u32 reg_mask; 103 unsigned int reg; 104 105 tps65910_reg_read(tps65910, TPS65910_INT_MSK, &reg); 106 reg_mask = reg; 107 tps65910_reg_read(tps65910, TPS65910_INT_MSK2, &reg); 108 reg_mask |= reg << 8; 109 switch (tps65910_chip_id(tps65910)) { 110 case TPS65911: 111 tps65910_reg_read(tps65910, TPS65910_INT_MSK3, &reg); 112 reg_mask |= reg << 16; 113 } 114 115 if (tps65910->irq_mask != reg_mask) { 116 reg = tps65910->irq_mask & 0xFF; 117 tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg); 118 reg = tps65910->irq_mask >> 8 & 0xFF; 119 tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg); 120 switch (tps65910_chip_id(tps65910)) { 121 case TPS65911: 122 reg = tps65910->irq_mask >> 16; 123 tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg); 124 } 125 } 126 mutex_unlock(&tps65910->irq_lock); 127} 128 129static void tps65910_irq_enable(struct irq_data *data) 130{ 131 struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); 132 133 tps65910->irq_mask &= ~(1 << data->hwirq); 134} 135 136static void tps65910_irq_disable(struct irq_data *data) 137{ 138 struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); 139 140 tps65910->irq_mask |= (1 << data->hwirq); 141} 142 143#ifdef CONFIG_PM_SLEEP 144static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable) 145{ 146 struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); 147 return irq_set_irq_wake(tps65910->chip_irq, enable); 148} 149#else 150#define tps65910_irq_set_wake NULL 151#endif 152 153static struct irq_chip tps65910_irq_chip = { 154 .name = "tps65910", 155 .irq_bus_lock = tps65910_irq_lock, 156 .irq_bus_sync_unlock = tps65910_irq_sync_unlock, 157 .irq_disable = tps65910_irq_disable, 158 .irq_enable = tps65910_irq_enable, 159 .irq_set_wake = tps65910_irq_set_wake, 160}; 161 162static int tps65910_irq_map(struct irq_domain *h, unsigned int virq, 163 irq_hw_number_t hw) 164{ 165 struct tps65910 *tps65910 = h->host_data; 166 167 irq_set_chip_data(virq, tps65910); 168 irq_set_chip_and_handler(virq, &tps65910_irq_chip, handle_edge_irq); 169 irq_set_nested_thread(virq, 1); 170 171 /* ARM needs us to explicitly flag the IRQ as valid 172 * and will set them noprobe when we do so. */ 173#ifdef CONFIG_ARM 174 set_irq_flags(virq, IRQF_VALID); 175#else 176 irq_set_noprobe(virq); 177#endif 178 179 return 0; 180} 181 182static struct irq_domain_ops tps65910_domain_ops = { 183 .map = tps65910_irq_map, 184 .xlate = irq_domain_xlate_twocell, 185}; 186 187int tps65910_irq_init(struct tps65910 *tps65910, int irq, 188 struct tps65910_platform_data *pdata) 189{ 190 int ret; 191 int flags = IRQF_ONESHOT; 192 193 if (!irq) { 194 dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); 195 return -EINVAL; 196 } 197 198 if (!pdata) { 199 dev_warn(tps65910->dev, "No interrupt support, no pdata\n"); 200 return -EINVAL; 201 } 202 203 switch (tps65910_chip_id(tps65910)) { 204 case TPS65910: 205 tps65910->irq_num = TPS65910_NUM_IRQ; 206 break; 207 case TPS65911: 208 tps65910->irq_num = TPS65911_NUM_IRQ; 209 break; 210 } 211 212 if (pdata->irq_base > 0) { 213 pdata->irq_base = irq_alloc_descs(pdata->irq_base, 0, 214 tps65910->irq_num, -1); 215 if (pdata->irq_base < 0) { 216 dev_warn(tps65910->dev, "Failed to alloc IRQs: %d\n", 217 pdata->irq_base); 218 return pdata->irq_base; 219 } 220 } 221 222 tps65910->irq_mask = 0xFFFFFF; 223 224 mutex_init(&tps65910->irq_lock); 225 tps65910->chip_irq = irq; 226 tps65910->irq_base = pdata->irq_base; 227 228 if (pdata->irq_base > 0) 229 tps65910->domain = irq_domain_add_legacy(tps65910->dev->of_node, 230 tps65910->irq_num, 231 pdata->irq_base, 232 0, 233 &tps65910_domain_ops, tps65910); 234 else 235 tps65910->domain = irq_domain_add_linear(tps65910->dev->of_node, 236 tps65910->irq_num, 237 &tps65910_domain_ops, tps65910); 238 239 if (!tps65910->domain) { 240 dev_err(tps65910->dev, "Failed to create IRQ domain\n"); 241 return -ENOMEM; 242 } 243 244 ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, 245 "tps65910", tps65910); 246 247 irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); 248 249 if (ret != 0) 250 dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret); 251 252 return ret; 253} 254 255int tps65910_irq_exit(struct tps65910 *tps65910) 256{ 257 if (tps65910->chip_irq) 258 free_irq(tps65910->chip_irq, tps65910); 259 return 0; 260}