aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/tps6586x.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-16 21:55:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-16 21:55:20 -0500
commit2dfea3803dcf70983d14ce1dcbb3e97a7459a28b (patch)
tree59bffc7389ff554585f79d7cc06021790dc2b317 /drivers/mfd/tps6586x.c
parentaed606e3bc1f10753254db308d3fd8c053c41328 (diff)
parent1881b68b8961a86d40c3c5c205e533515a2dc9c6 (diff)
Merge tag 'mfd-3.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
Pull MFS update from Samuel Ortiz: "This is the MFD patch set for the 3.8 merge window. We have several new drivers, most of the time coming with their sub devices drivers: - Austria Microsystem's AS3711 - Nano River's viperboard - TI's TPS80031, AM335x TS/ADC, - Realtek's MMC/memstick card reader - Nokia's retu We also got some notable cleanups and improvements: - tps6586x got converted to IRQ domains. - tps65910 and tps65090 moved to the regmap IRQ API. - STMPE is now Device Tree aware. - A general twl6040 and twl-core cleanup, with moves to the regmap I/O and IRQ APIs and a conversion to the recently added PWM framework. - sta2x11 gained regmap support. Then the rest is mostly tiny cleanups and fixes, among which we have Mark's wm5xxx and wm8xxx patchset." Far amount of annoying but largely trivial conflicts. Many due to __devinit/exit removal, others due to one or two of the new drivers also having come in through another tree. * tag 'mfd-3.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (119 commits) mfd: tps6507x: Convert to devm_kzalloc mfd: stmpe: Update DT support for stmpe driver mfd: wm5102: Add readback of DSP status 3 register mfd: arizona: Log if we fail to create the primary IRQ domain mfd: tps80031: MFD_TPS80031 needs to select REGMAP_IRQ mfd: tps80031: Add terminating entry for tps80031_id_table mfd: sta2x11: Fix potential NULL pointer dereference in __sta2x11_mfd_mask() mfd: wm5102: Add tuning for revision B mfd: arizona: Defer patch initialistation until after first device boot mfd: tps65910: Fix wrong ack_base register mfd: tps65910: Remove unused data mfd: stmpe: Get rid of irq_invert_polarity mfd: ab8500-core: Fix invalid free of devm_ allocated data mfd: wm5102: Mark DSP memory regions as volatile mfd: wm5102: Correct default for LDO1_CONTROL_2 mfd: arizona: Register haptics devices mfd: wm8994: Make current device behaviour the default mfd: tps65090: MFD_TPS65090 needs to select REGMAP_IRQ mfd: Fix stmpe.c build when OF is not enabled mfd: jz4740-adc: Use devm_kzalloc ...
Diffstat (limited to 'drivers/mfd/tps6586x.c')
-rw-r--r--drivers/mfd/tps6586x.c103
1 files changed, 77 insertions, 26 deletions
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 87ba7ada3bbc..721b9186a5d1 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -17,12 +17,14 @@
17 17
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/irqdomain.h>
20#include <linux/kernel.h> 21#include <linux/kernel.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/mutex.h> 23#include <linux/mutex.h>
23#include <linux/slab.h> 24#include <linux/slab.h>
24#include <linux/err.h> 25#include <linux/err.h>
25#include <linux/i2c.h> 26#include <linux/i2c.h>
27#include <linux/platform_device.h>
26#include <linux/regmap.h> 28#include <linux/regmap.h>
27 29
28#include <linux/mfd/core.h> 30#include <linux/mfd/core.h>
@@ -92,6 +94,14 @@ static const struct tps6586x_irq_data tps6586x_irqs[] = {
92 [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1), 94 [TPS6586X_INT_RTC_ALM2] = TPS6586X_IRQ(TPS6586X_INT_MASK4, 1 << 1),
93}; 95};
94 96
97static struct resource tps6586x_rtc_resources[] = {
98 {
99 .start = TPS6586X_INT_RTC_ALM1,
100 .end = TPS6586X_INT_RTC_ALM1,
101 .flags = IORESOURCE_IRQ,
102 },
103};
104
95static struct mfd_cell tps6586x_cell[] = { 105static struct mfd_cell tps6586x_cell[] = {
96 { 106 {
97 .name = "tps6586x-gpio", 107 .name = "tps6586x-gpio",
@@ -101,6 +111,8 @@ static struct mfd_cell tps6586x_cell[] = {
101 }, 111 },
102 { 112 {
103 .name = "tps6586x-rtc", 113 .name = "tps6586x-rtc",
114 .num_resources = ARRAY_SIZE(tps6586x_rtc_resources),
115 .resources = &tps6586x_rtc_resources[0],
104 }, 116 },
105 { 117 {
106 .name = "tps6586x-onkey", 118 .name = "tps6586x-onkey",
@@ -117,6 +129,7 @@ struct tps6586x {
117 int irq_base; 129 int irq_base;
118 u32 irq_en; 130 u32 irq_en;
119 u8 mask_reg[5]; 131 u8 mask_reg[5];
132 struct irq_domain *irq_domain;
120}; 133};
121 134
122static inline struct tps6586x *dev_to_tps6586x(struct device *dev) 135static inline struct tps6586x *dev_to_tps6586x(struct device *dev)
@@ -185,6 +198,14 @@ int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
185} 198}
186EXPORT_SYMBOL_GPL(tps6586x_update); 199EXPORT_SYMBOL_GPL(tps6586x_update);
187 200
201int tps6586x_irq_get_virq(struct device *dev, int irq)
202{
203 struct tps6586x *tps6586x = dev_to_tps6586x(dev);
204
205 return irq_create_mapping(tps6586x->irq_domain, irq);
206}
207EXPORT_SYMBOL_GPL(tps6586x_irq_get_virq);
208
188static int __remove_subdev(struct device *dev, void *unused) 209static int __remove_subdev(struct device *dev, void *unused)
189{ 210{
190 platform_device_unregister(to_platform_device(dev)); 211 platform_device_unregister(to_platform_device(dev));
@@ -206,7 +227,7 @@ static void tps6586x_irq_lock(struct irq_data *data)
206static void tps6586x_irq_enable(struct irq_data *irq_data) 227static void tps6586x_irq_enable(struct irq_data *irq_data)
207{ 228{
208 struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); 229 struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
209 unsigned int __irq = irq_data->irq - tps6586x->irq_base; 230 unsigned int __irq = irq_data->hwirq;
210 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; 231 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
211 232
212 tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask; 233 tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
@@ -217,7 +238,7 @@ static void tps6586x_irq_disable(struct irq_data *irq_data)
217{ 238{
218 struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data); 239 struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
219 240
220 unsigned int __irq = irq_data->irq - tps6586x->irq_base; 241 unsigned int __irq = irq_data->hwirq;
221 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq]; 242 const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
222 243
223 tps6586x->mask_reg[data->mask_reg] |= data->mask_mask; 244 tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
@@ -240,6 +261,39 @@ static void tps6586x_irq_sync_unlock(struct irq_data *data)
240 mutex_unlock(&tps6586x->irq_lock); 261 mutex_unlock(&tps6586x->irq_lock);
241} 262}
242 263
264static struct irq_chip tps6586x_irq_chip = {
265 .name = "tps6586x",
266 .irq_bus_lock = tps6586x_irq_lock,
267 .irq_bus_sync_unlock = tps6586x_irq_sync_unlock,
268 .irq_disable = tps6586x_irq_disable,
269 .irq_enable = tps6586x_irq_enable,
270};
271
272static int tps6586x_irq_map(struct irq_domain *h, unsigned int virq,
273 irq_hw_number_t hw)
274{
275 struct tps6586x *tps6586x = h->host_data;
276
277 irq_set_chip_data(virq, tps6586x);
278 irq_set_chip_and_handler(virq, &tps6586x_irq_chip, handle_simple_irq);
279 irq_set_nested_thread(virq, 1);
280
281 /* ARM needs us to explicitly flag the IRQ as valid
282 * and will set them noprobe when we do so. */
283#ifdef CONFIG_ARM
284 set_irq_flags(virq, IRQF_VALID);
285#else
286 irq_set_noprobe(virq);
287#endif
288
289 return 0;
290}
291
292static struct irq_domain_ops tps6586x_domain_ops = {
293 .map = tps6586x_irq_map,
294 .xlate = irq_domain_xlate_twocell,
295};
296
243static irqreturn_t tps6586x_irq(int irq, void *data) 297static irqreturn_t tps6586x_irq(int irq, void *data)
244{ 298{
245 struct tps6586x *tps6586x = data; 299 struct tps6586x *tps6586x = data;
@@ -260,7 +314,8 @@ static irqreturn_t tps6586x_irq(int irq, void *data)
260 int i = __ffs(acks); 314 int i = __ffs(acks);
261 315
262 if (tps6586x->irq_en & (1 << i)) 316 if (tps6586x->irq_en & (1 << i))
263 handle_nested_irq(tps6586x->irq_base + i); 317 handle_nested_irq(
318 irq_find_mapping(tps6586x->irq_domain, i));
264 319
265 acks &= ~(1 << i); 320 acks &= ~(1 << i);
266 } 321 }
@@ -273,11 +328,8 @@ static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
273{ 328{
274 int i, ret; 329 int i, ret;
275 u8 tmp[4]; 330 u8 tmp[4];
276 331 int new_irq_base;
277 if (!irq_base) { 332 int irq_num = ARRAY_SIZE(tps6586x_irqs);
278 dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n");
279 return -EINVAL;
280 }
281 333
282 mutex_init(&tps6586x->irq_lock); 334 mutex_init(&tps6586x->irq_lock);
283 for (i = 0; i < 5; i++) { 335 for (i = 0; i < 5; i++) {
@@ -287,25 +339,24 @@ static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
287 339
288 tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp); 340 tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp);
289 341
290 tps6586x->irq_base = irq_base; 342 if (irq_base > 0) {
291 343 new_irq_base = irq_alloc_descs(irq_base, 0, irq_num, -1);
292 tps6586x->irq_chip.name = "tps6586x"; 344 if (new_irq_base < 0) {
293 tps6586x->irq_chip.irq_enable = tps6586x_irq_enable; 345 dev_err(tps6586x->dev,
294 tps6586x->irq_chip.irq_disable = tps6586x_irq_disable; 346 "Failed to alloc IRQs: %d\n", new_irq_base);
295 tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock; 347 return new_irq_base;
296 tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock; 348 }
297 349 } else {
298 for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { 350 new_irq_base = 0;
299 int __irq = i + tps6586x->irq_base;
300 irq_set_chip_data(__irq, tps6586x);
301 irq_set_chip_and_handler(__irq, &tps6586x->irq_chip,
302 handle_simple_irq);
303 irq_set_nested_thread(__irq, 1);
304#ifdef CONFIG_ARM
305 set_irq_flags(__irq, IRQF_VALID);
306#endif
307 } 351 }
308 352
353 tps6586x->irq_domain = irq_domain_add_simple(tps6586x->dev->of_node,
354 irq_num, new_irq_base, &tps6586x_domain_ops,
355 tps6586x);
356 if (!tps6586x->irq_domain) {
357 dev_err(tps6586x->dev, "Failed to create IRQ domain\n");
358 return -ENOMEM;
359 }
309 ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT, 360 ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT,
310 "tps6586x", tps6586x); 361 "tps6586x", tps6586x);
311 362
@@ -461,7 +512,7 @@ static int tps6586x_i2c_probe(struct i2c_client *client,
461 512
462 ret = mfd_add_devices(tps6586x->dev, -1, 513 ret = mfd_add_devices(tps6586x->dev, -1,
463 tps6586x_cell, ARRAY_SIZE(tps6586x_cell), 514 tps6586x_cell, ARRAY_SIZE(tps6586x_cell),
464 NULL, 0, NULL); 515 NULL, 0, tps6586x->irq_domain);
465 if (ret < 0) { 516 if (ret < 0) {
466 dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); 517 dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret);
467 goto err_mfd_add; 518 goto err_mfd_add;