aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2012-10-11 07:55:32 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-11-13 13:54:23 -0500
commitab7edb149c7548541ee588b8372c2041b6f1cbc8 (patch)
tree12bff6036c4eed3683e007e3fa890d1453666edf
parent1ac96265a6f35080083e85b0f58182cdc9c07d0e (diff)
mfd: twl6040: Convert to use regmap_irq
With regmap_irq it is possible to remove the twl6040-irq.c file and simplify the code. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/Kconfig4
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/twl6040-core.c55
-rw-r--r--drivers/mfd/twl6040-irq.c205
-rw-r--r--include/linux/mfd/twl6040.h10
5 files changed, 48 insertions, 228 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3f2187ae8c5d..34242cada125 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -321,10 +321,10 @@ config MFD_TWL4030_AUDIO
321 321
322config TWL6040_CORE 322config TWL6040_CORE
323 bool "Support for TWL6040 audio codec" 323 bool "Support for TWL6040 audio codec"
324 depends on I2C=y && GENERIC_HARDIRQS 324 depends on I2C=y
325 select MFD_CORE 325 select MFD_CORE
326 select REGMAP_I2C 326 select REGMAP_I2C
327 select IRQ_DOMAIN 327 select REGMAP_IRQ
328 default n 328 default n
329 help 329 help
330 Say yes here if you want support for Texas Instruments TWL6040 audio 330 Say yes here if you want support for Texas Instruments TWL6040 audio
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a4093a44304a..05bebf66ccd2 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -67,7 +67,7 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
67obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o 67obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
68obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o 68obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
69obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o 69obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
70obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o 70obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o
71 71
72obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o 72obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
73obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o 73obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index 5817bc6d09dc..e5f7b795afff 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -499,6 +499,25 @@ static struct regmap_config twl6040_regmap_config = {
499 .readable_reg = twl6040_readable_reg, 499 .readable_reg = twl6040_readable_reg,
500}; 500};
501 501
502static const struct regmap_irq twl6040_irqs[] = {
503 { .reg_offset = 0, .mask = TWL6040_THINT, },
504 { .reg_offset = 0, .mask = TWL6040_PLUGINT | TWL6040_UNPLUGINT, },
505 { .reg_offset = 0, .mask = TWL6040_HOOKINT, },
506 { .reg_offset = 0, .mask = TWL6040_HFINT, },
507 { .reg_offset = 0, .mask = TWL6040_VIBINT, },
508 { .reg_offset = 0, .mask = TWL6040_READYINT, },
509};
510
511static struct regmap_irq_chip twl6040_irq_chip = {
512 .name = "twl6040",
513 .irqs = twl6040_irqs,
514 .num_irqs = ARRAY_SIZE(twl6040_irqs),
515
516 .num_regs = 1,
517 .status_base = TWL6040_REG_INTID,
518 .mask_base = TWL6040_REG_INTMR,
519};
520
502static int __devinit twl6040_probe(struct i2c_client *client, 521static int __devinit twl6040_probe(struct i2c_client *client,
503 const struct i2c_device_id *id) 522 const struct i2c_device_id *id)
504{ 523{
@@ -574,21 +593,27 @@ static int __devinit twl6040_probe(struct i2c_client *client,
574 goto gpio_err; 593 goto gpio_err;
575 } 594 }
576 595
577 /* codec interrupt */ 596 ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq,
578 ret = twl6040_irq_init(twl6040); 597 IRQF_ONESHOT, 0, &twl6040_irq_chip,
579 if (ret) 598 &twl6040->irq_data);
599 if (ret < 0)
580 goto irq_init_err; 600 goto irq_init_err;
581 601
582 ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, 602 twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data,
583 NULL, twl6040_readyint_handler, IRQF_ONESHOT, 603 TWL6040_IRQ_READY);
604 twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data,
605 TWL6040_IRQ_TH);
606
607 ret = request_threaded_irq(twl6040->irq_ready, NULL,
608 twl6040_readyint_handler, IRQF_ONESHOT,
584 "twl6040_irq_ready", twl6040); 609 "twl6040_irq_ready", twl6040);
585 if (ret) { 610 if (ret) {
586 dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); 611 dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret);
587 goto readyirq_err; 612 goto readyirq_err;
588 } 613 }
589 614
590 ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_TH, 615 ret = request_threaded_irq(twl6040->irq_th, NULL,
591 NULL, twl6040_thint_handler, IRQF_ONESHOT, 616 twl6040_thint_handler, IRQF_ONESHOT,
592 "twl6040_irq_th", twl6040); 617 "twl6040_irq_th", twl6040);
593 if (ret) { 618 if (ret) {
594 dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); 619 dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret);
@@ -604,7 +629,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
604 * The ASoC codec can work without pdata, pass the platform_data only if 629 * The ASoC codec can work without pdata, pass the platform_data only if
605 * it has been provided. 630 * it has been provided.
606 */ 631 */
607 irq = twl6040->irq_base + TWL6040_IRQ_PLUG; 632 irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG);
608 cell = &twl6040->cells[children]; 633 cell = &twl6040->cells[children];
609 cell->name = "twl6040-codec"; 634 cell->name = "twl6040-codec";
610 twl6040_codec_rsrc[0].start = irq; 635 twl6040_codec_rsrc[0].start = irq;
@@ -618,7 +643,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
618 children++; 643 children++;
619 644
620 if (twl6040_has_vibra(pdata, node)) { 645 if (twl6040_has_vibra(pdata, node)) {
621 irq = twl6040->irq_base + TWL6040_IRQ_VIB; 646 irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB);
622 647
623 cell = &twl6040->cells[children]; 648 cell = &twl6040->cells[children];
624 cell->name = "twl6040-vibra"; 649 cell->name = "twl6040-vibra";
@@ -657,11 +682,11 @@ static int __devinit twl6040_probe(struct i2c_client *client,
657 return 0; 682 return 0;
658 683
659mfd_err: 684mfd_err:
660 free_irq(twl6040->irq_base + TWL6040_IRQ_TH, twl6040); 685 free_irq(twl6040->irq_th, twl6040);
661thirq_err: 686thirq_err:
662 free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); 687 free_irq(twl6040->irq_ready, twl6040);
663readyirq_err: 688readyirq_err:
664 twl6040_irq_exit(twl6040); 689 regmap_del_irq_chip(twl6040->irq, twl6040->irq_data);
665irq_init_err: 690irq_init_err:
666 if (gpio_is_valid(twl6040->audpwron)) 691 if (gpio_is_valid(twl6040->audpwron))
667 gpio_free(twl6040->audpwron); 692 gpio_free(twl6040->audpwron);
@@ -685,9 +710,9 @@ static int __devexit twl6040_remove(struct i2c_client *client)
685 if (gpio_is_valid(twl6040->audpwron)) 710 if (gpio_is_valid(twl6040->audpwron))
686 gpio_free(twl6040->audpwron); 711 gpio_free(twl6040->audpwron);
687 712
688 free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); 713 free_irq(twl6040->irq_ready, twl6040);
689 free_irq(twl6040->irq_base + TWL6040_IRQ_TH, twl6040); 714 free_irq(twl6040->irq_th, twl6040);
690 twl6040_irq_exit(twl6040); 715 regmap_del_irq_chip(twl6040->irq, twl6040->irq_data);
691 716
692 mfd_remove_devices(&client->dev); 717 mfd_remove_devices(&client->dev);
693 i2c_set_clientdata(client, NULL); 718 i2c_set_clientdata(client, NULL);
diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
deleted file mode 100644
index 4b42543da228..000000000000
--- a/drivers/mfd/twl6040-irq.c
+++ /dev/null
@@ -1,205 +0,0 @@
1/*
2 * Interrupt controller support for TWL6040
3 *
4 * Author: Misael Lopez Cruz <misael.lopez@ti.com>
5 *
6 * Copyright: (C) 2011 Texas Instruments, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/err.h>
27#include <linux/irq.h>
28#include <linux/of.h>
29#include <linux/irqdomain.h>
30#include <linux/interrupt.h>
31#include <linux/mfd/core.h>
32#include <linux/mfd/twl6040.h>
33
34struct twl6040_irq_data {
35 int mask;
36 int status;
37};
38
39static struct twl6040_irq_data twl6040_irqs[] = {
40 {
41 .mask = TWL6040_THMSK,
42 .status = TWL6040_THINT,
43 },
44 {
45 .mask = TWL6040_PLUGMSK,
46 .status = TWL6040_PLUGINT | TWL6040_UNPLUGINT,
47 },
48 {
49 .mask = TWL6040_HOOKMSK,
50 .status = TWL6040_HOOKINT,
51 },
52 {
53 .mask = TWL6040_HFMSK,
54 .status = TWL6040_HFINT,
55 },
56 {
57 .mask = TWL6040_VIBMSK,
58 .status = TWL6040_VIBINT,
59 },
60 {
61 .mask = TWL6040_READYMSK,
62 .status = TWL6040_READYINT,
63 },
64};
65
66static inline
67struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040,
68 int irq)
69{
70 return &twl6040_irqs[irq - twl6040->irq_base];
71}
72
73static void twl6040_irq_lock(struct irq_data *data)
74{
75 struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
76
77 mutex_lock(&twl6040->irq_mutex);
78}
79
80static void twl6040_irq_sync_unlock(struct irq_data *data)
81{
82 struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
83
84 /* write back to hardware any change in irq mask */
85 if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) {
86 twl6040->irq_masks_cache = twl6040->irq_masks_cur;
87 twl6040_reg_write(twl6040, TWL6040_REG_INTMR,
88 twl6040->irq_masks_cur);
89 }
90
91 mutex_unlock(&twl6040->irq_mutex);
92}
93
94static void twl6040_irq_enable(struct irq_data *data)
95{
96 struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
97 struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
98 data->irq);
99
100 twl6040->irq_masks_cur &= ~irq_data->mask;
101}
102
103static void twl6040_irq_disable(struct irq_data *data)
104{
105 struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
106 struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
107 data->irq);
108
109 twl6040->irq_masks_cur |= irq_data->mask;
110}
111
112static struct irq_chip twl6040_irq_chip = {
113 .name = "twl6040",
114 .irq_bus_lock = twl6040_irq_lock,
115 .irq_bus_sync_unlock = twl6040_irq_sync_unlock,
116 .irq_enable = twl6040_irq_enable,
117 .irq_disable = twl6040_irq_disable,
118};
119
120static irqreturn_t twl6040_irq_thread(int irq, void *data)
121{
122 struct twl6040 *twl6040 = data;
123 u8 intid;
124 int i;
125
126 intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
127
128 /* apply masking and report (backwards to handle READYINT first) */
129 for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) {
130 if (twl6040->irq_masks_cur & twl6040_irqs[i].mask)
131 intid &= ~twl6040_irqs[i].status;
132 if (intid & twl6040_irqs[i].status)
133 handle_nested_irq(twl6040->irq_base + i);
134 }
135
136 /* ack unmasked irqs */
137 twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid);
138
139 return IRQ_HANDLED;
140}
141
142int twl6040_irq_init(struct twl6040 *twl6040)
143{
144 struct device_node *node = twl6040->dev->of_node;
145 int i, nr_irqs, irq_base, ret;
146 u8 val;
147
148 mutex_init(&twl6040->irq_mutex);
149
150 /* mask the individual interrupt sources */
151 twl6040->irq_masks_cur = TWL6040_ALLINT_MSK;
152 twl6040->irq_masks_cache = TWL6040_ALLINT_MSK;
153 twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);
154
155 nr_irqs = ARRAY_SIZE(twl6040_irqs);
156
157 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
158 if (IS_ERR_VALUE(irq_base)) {
159 dev_err(twl6040->dev, "Fail to allocate IRQ descs\n");
160 return irq_base;
161 }
162 twl6040->irq_base = irq_base;
163
164 irq_domain_add_legacy(node, ARRAY_SIZE(twl6040_irqs), irq_base, 0,
165 &irq_domain_simple_ops, NULL);
166
167 /* Register them with genirq */
168 for (i = irq_base; i < irq_base + nr_irqs; i++) {
169 irq_set_chip_data(i, twl6040);
170 irq_set_chip_and_handler(i, &twl6040_irq_chip,
171 handle_level_irq);
172 irq_set_nested_thread(i, 1);
173
174 /* ARM needs us to explicitly flag the IRQ as valid
175 * and will set them noprobe when we do so. */
176#ifdef CONFIG_ARM
177 set_irq_flags(i, IRQF_VALID);
178#else
179 irq_set_noprobe(i);
180#endif
181 }
182
183 ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread,
184 IRQF_ONESHOT, "twl6040", twl6040);
185 if (ret) {
186 dev_err(twl6040->dev, "failed to request IRQ %d: %d\n",
187 twl6040->irq, ret);
188 return ret;
189 }
190
191 /* reset interrupts */
192 val = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
193
194 /* interrupts cleared on write */
195 twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_INTCLRMODE);
196
197 return 0;
198}
199EXPORT_SYMBOL(twl6040_irq_init);
200
201void twl6040_irq_exit(struct twl6040 *twl6040)
202{
203 free_irq(twl6040->irq, twl6040);
204}
205EXPORT_SYMBOL(twl6040_irq_exit);
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h
index a8eff4ad9be5..94ac944d12f0 100644
--- a/include/linux/mfd/twl6040.h
+++ b/include/linux/mfd/twl6040.h
@@ -207,10 +207,12 @@ struct twl6040_platform_data {
207}; 207};
208 208
209struct regmap; 209struct regmap;
210struct regmap_irq_chips_data;
210 211
211struct twl6040 { 212struct twl6040 {
212 struct device *dev; 213 struct device *dev;
213 struct regmap *regmap; 214 struct regmap *regmap;
215 struct regmap_irq_chip_data *irq_data;
214 struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */ 216 struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */
215 struct mutex mutex; 217 struct mutex mutex;
216 struct mutex irq_mutex; 218 struct mutex irq_mutex;
@@ -228,9 +230,8 @@ struct twl6040 {
228 unsigned int mclk; 230 unsigned int mclk;
229 231
230 unsigned int irq; 232 unsigned int irq;
231 unsigned int irq_base; 233 unsigned int irq_ready;
232 u8 irq_masks_cur; 234 unsigned int irq_th;
233 u8 irq_masks_cache;
234}; 235};
235 236
236int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg); 237int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg);
@@ -245,8 +246,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
245 unsigned int freq_in, unsigned int freq_out); 246 unsigned int freq_in, unsigned int freq_out);
246int twl6040_get_pll(struct twl6040 *twl6040); 247int twl6040_get_pll(struct twl6040 *twl6040);
247unsigned int twl6040_get_sysclk(struct twl6040 *twl6040); 248unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
248int twl6040_irq_init(struct twl6040 *twl6040); 249
249void twl6040_irq_exit(struct twl6040 *twl6040);
250/* Get the combined status of the vibra control register */ 250/* Get the combined status of the vibra control register */
251int twl6040_get_vibralr_status(struct twl6040 *twl6040); 251int twl6040_get_vibralr_status(struct twl6040 *twl6040);
252 252