aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/tps6586x.c
diff options
context:
space:
mode:
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 87ba7ada3bb..721b9186a5d 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;