diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 21:55:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 21:55:20 -0500 |
commit | 2dfea3803dcf70983d14ce1dcbb3e97a7459a28b (patch) | |
tree | 59bffc7389ff554585f79d7cc06021790dc2b317 /drivers/mfd/tps6586x.c | |
parent | aed606e3bc1f10753254db308d3fd8c053c41328 (diff) | |
parent | 1881b68b8961a86d40c3c5c205e533515a2dc9c6 (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.c | 103 |
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 | ||
97 | static 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 | |||
95 | static struct mfd_cell tps6586x_cell[] = { | 105 | static 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 | ||
122 | static inline struct tps6586x *dev_to_tps6586x(struct device *dev) | 135 | static 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 | } |
186 | EXPORT_SYMBOL_GPL(tps6586x_update); | 199 | EXPORT_SYMBOL_GPL(tps6586x_update); |
187 | 200 | ||
201 | int 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 | } | ||
207 | EXPORT_SYMBOL_GPL(tps6586x_irq_get_virq); | ||
208 | |||
188 | static int __remove_subdev(struct device *dev, void *unused) | 209 | static 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) | |||
206 | static void tps6586x_irq_enable(struct irq_data *irq_data) | 227 | static 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 | ||
264 | static 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 | |||
272 | static 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 | |||
292 | static struct irq_domain_ops tps6586x_domain_ops = { | ||
293 | .map = tps6586x_irq_map, | ||
294 | .xlate = irq_domain_xlate_twocell, | ||
295 | }; | ||
296 | |||
243 | static irqreturn_t tps6586x_irq(int irq, void *data) | 297 | static 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; |