diff options
| author | Tomasz Figa <t.figa@samsung.com> | 2013-06-24 08:39:52 -0400 |
|---|---|---|
| committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-06-30 17:29:44 -0400 |
| commit | 443c6ae253e96db9a5800a28d7c61131e81c2dee (patch) | |
| tree | c9df532a7f81a8799fe52f6845504b275803e58e /drivers | |
| parent | b5c46787df1f28b0a24499e275491ba9a505c8ec (diff) | |
mfd: max8998: Add irq domain support
This patch adds irq domain support for max8998 interrupts.
To keep both non-DT and DT worlds happy, simple domain is used, which is
linear when no explicit IRQ base is specified and legacy, with static
mapping, otherwise.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mfd/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/mfd/max8998-irq.c | 65 | ||||
| -rw-r--r-- | drivers/rtc/rtc-max8998.c | 12 |
3 files changed, 52 insertions, 26 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3bb2932eafb1..aecd6ddcbbbf 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -363,6 +363,7 @@ config MFD_MAX8998 | |||
| 363 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | 363 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" |
| 364 | depends on I2C=y && GENERIC_HARDIRQS | 364 | depends on I2C=y && GENERIC_HARDIRQS |
| 365 | select MFD_CORE | 365 | select MFD_CORE |
| 366 | select IRQ_DOMAIN | ||
| 366 | help | 367 | help |
| 367 | Say yes here to support for Maxim Semiconductor MAX8998 and | 368 | Say yes here to support for Maxim Semiconductor MAX8998 and |
| 368 | National Semiconductor LP3974. This is a Power Management IC. | 369 | National Semiconductor LP3974. This is a Power Management IC. |
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 5919710dc9ed..c469477eb778 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 16 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
| 17 | #include <linux/irqdomain.h> | ||
| 17 | #include <linux/mfd/max8998-private.h> | 18 | #include <linux/mfd/max8998-private.h> |
| 18 | 19 | ||
| 19 | struct max8998_irq_data { | 20 | struct max8998_irq_data { |
| @@ -99,7 +100,8 @@ static struct max8998_irq_data max8998_irqs[] = { | |||
| 99 | static inline struct max8998_irq_data * | 100 | static inline struct max8998_irq_data * |
| 100 | irq_to_max8998_irq(struct max8998_dev *max8998, int irq) | 101 | irq_to_max8998_irq(struct max8998_dev *max8998, int irq) |
| 101 | { | 102 | { |
| 102 | return &max8998_irqs[irq - max8998->irq_base]; | 103 | struct irq_data *data = irq_get_irq_data(irq); |
| 104 | return &max8998_irqs[data->hwirq]; | ||
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | static void max8998_irq_lock(struct irq_data *data) | 107 | static void max8998_irq_lock(struct irq_data *data) |
| @@ -176,8 +178,14 @@ static irqreturn_t max8998_irq_thread(int irq, void *data) | |||
| 176 | 178 | ||
| 177 | /* Report */ | 179 | /* Report */ |
| 178 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | 180 | for (i = 0; i < MAX8998_IRQ_NR; i++) { |
| 179 | if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) | 181 | if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) { |
| 180 | handle_nested_irq(max8998->irq_base + i); | 182 | irq = irq_find_mapping(max8998->irq_domain, i); |
| 183 | if (WARN_ON(!irq)) { | ||
| 184 | disable_irq_nosync(max8998->irq); | ||
| 185 | return IRQ_NONE; | ||
| 186 | } | ||
| 187 | handle_nested_irq(irq); | ||
| 188 | } | ||
| 181 | } | 189 | } |
| 182 | 190 | ||
| 183 | return IRQ_HANDLED; | 191 | return IRQ_HANDLED; |
| @@ -185,27 +193,40 @@ static irqreturn_t max8998_irq_thread(int irq, void *data) | |||
| 185 | 193 | ||
| 186 | int max8998_irq_resume(struct max8998_dev *max8998) | 194 | int max8998_irq_resume(struct max8998_dev *max8998) |
| 187 | { | 195 | { |
| 188 | if (max8998->irq && max8998->irq_base) | 196 | if (max8998->irq && max8998->irq_domain) |
| 189 | max8998_irq_thread(max8998->irq_base, max8998); | 197 | max8998_irq_thread(max8998->irq, max8998); |
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static int max8998_irq_domain_map(struct irq_domain *d, unsigned int irq, | ||
| 202 | irq_hw_number_t hw) | ||
| 203 | { | ||
| 204 | struct max8997_dev *max8998 = d->host_data; | ||
| 205 | |||
| 206 | irq_set_chip_data(irq, max8998); | ||
| 207 | irq_set_chip_and_handler(irq, &max8998_irq_chip, handle_edge_irq); | ||
| 208 | irq_set_nested_thread(irq, 1); | ||
| 209 | #ifdef CONFIG_ARM | ||
| 210 | set_irq_flags(irq, IRQF_VALID); | ||
| 211 | #else | ||
| 212 | irq_set_noprobe(irq); | ||
| 213 | #endif | ||
| 190 | return 0; | 214 | return 0; |
| 191 | } | 215 | } |
| 192 | 216 | ||
| 217 | static struct irq_domain_ops max8998_irq_domain_ops = { | ||
| 218 | .map = max8998_irq_domain_map, | ||
| 219 | }; | ||
| 220 | |||
| 193 | int max8998_irq_init(struct max8998_dev *max8998) | 221 | int max8998_irq_init(struct max8998_dev *max8998) |
| 194 | { | 222 | { |
| 195 | int i; | 223 | int i; |
| 196 | int cur_irq; | ||
| 197 | int ret; | 224 | int ret; |
| 225 | struct irq_domain *domain; | ||
| 198 | 226 | ||
| 199 | if (!max8998->irq) { | 227 | if (!max8998->irq) { |
| 200 | dev_warn(max8998->dev, | 228 | dev_warn(max8998->dev, |
| 201 | "No interrupt specified, no interrupts\n"); | 229 | "No interrupt specified, no interrupts\n"); |
| 202 | max8998->irq_base = 0; | ||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | if (!max8998->irq_base) { | ||
| 207 | dev_err(max8998->dev, | ||
| 208 | "No interrupt base specified, no interrupts\n"); | ||
| 209 | return 0; | 230 | return 0; |
| 210 | } | 231 | } |
| 211 | 232 | ||
| @@ -221,19 +242,13 @@ int max8998_irq_init(struct max8998_dev *max8998) | |||
| 221 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); | 242 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); |
| 222 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); | 243 | max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); |
| 223 | 244 | ||
| 224 | /* register with genirq */ | 245 | domain = irq_domain_add_simple(NULL, MAX8998_IRQ_NR, |
| 225 | for (i = 0; i < MAX8998_IRQ_NR; i++) { | 246 | max8998->irq_base, &max8998_irq_domain_ops, max8998); |
| 226 | cur_irq = i + max8998->irq_base; | 247 | if (!domain) { |
| 227 | irq_set_chip_data(cur_irq, max8998); | 248 | dev_err(max8998->dev, "could not create irq domain\n"); |
| 228 | irq_set_chip_and_handler(cur_irq, &max8998_irq_chip, | 249 | return -ENODEV; |
| 229 | handle_edge_irq); | ||
| 230 | irq_set_nested_thread(cur_irq, 1); | ||
| 231 | #ifdef CONFIG_ARM | ||
| 232 | set_irq_flags(cur_irq, IRQF_VALID); | ||
| 233 | #else | ||
| 234 | irq_set_noprobe(cur_irq); | ||
| 235 | #endif | ||
| 236 | } | 250 | } |
| 251 | max8998->irq_domain = domain; | ||
| 237 | 252 | ||
| 238 | ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread, | 253 | ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread, |
| 239 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 254 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index d5af7baa48b5..46f23014759b 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/bcd.h> | 18 | #include <linux/bcd.h> |
| 19 | #include <linux/irqdomain.h> | ||
| 19 | #include <linux/rtc.h> | 20 | #include <linux/rtc.h> |
| 20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 21 | #include <linux/mfd/max8998.h> | 22 | #include <linux/mfd/max8998.h> |
| @@ -264,7 +265,6 @@ static int max8998_rtc_probe(struct platform_device *pdev) | |||
| 264 | info->dev = &pdev->dev; | 265 | info->dev = &pdev->dev; |
| 265 | info->max8998 = max8998; | 266 | info->max8998 = max8998; |
| 266 | info->rtc = max8998->rtc; | 267 | info->rtc = max8998->rtc; |
| 267 | info->irq = max8998->irq_base + MAX8998_IRQ_ALARM0; | ||
| 268 | 268 | ||
| 269 | platform_set_drvdata(pdev, info); | 269 | platform_set_drvdata(pdev, info); |
| 270 | 270 | ||
| @@ -277,6 +277,15 @@ static int max8998_rtc_probe(struct platform_device *pdev) | |||
| 277 | goto out_rtc; | 277 | goto out_rtc; |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | if (!max8998->irq_domain) | ||
| 281 | goto no_irq; | ||
| 282 | |||
| 283 | info->irq = irq_create_mapping(max8998->irq_domain, MAX8998_IRQ_ALARM0); | ||
| 284 | if (!info->irq) { | ||
| 285 | dev_warn(&pdev->dev, "Failed to map alarm IRQ\n"); | ||
| 286 | goto no_irq; | ||
| 287 | } | ||
| 288 | |||
| 280 | ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, | 289 | ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, |
| 281 | max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); | 290 | max8998_rtc_alarm_irq, 0, "rtc-alarm0", info); |
| 282 | 291 | ||
| @@ -284,6 +293,7 @@ static int max8998_rtc_probe(struct platform_device *pdev) | |||
| 284 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", | 293 | dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", |
| 285 | info->irq, ret); | 294 | info->irq, ret); |
| 286 | 295 | ||
| 296 | no_irq: | ||
| 287 | dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); | 297 | dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); |
| 288 | if (pdata && pdata->rtc_delay) { | 298 | if (pdata && pdata->rtc_delay) { |
| 289 | info->lp3974_bug_workaround = true; | 299 | info->lp3974_bug_workaround = true; |
