mfd: Move twl-core IRQ allocation into twl[4030|6030]-irq files
During DT adaptation, the irq_alloc_desc was added into twl-core, but due to the rather different and weird IRQ management required by the twl4030, it is much better to have a different approach for it. The issue is that twl4030 uses a two level IRQ mechanism but handles all the PWR interrupts as part of the twl-core interrupt range. It ends up with a range of 16 interrupts total for CORE and PWR. The other twl4030 functionalities already have a dedicated driver and thus their IRQs and irqdomain can and should be defined localy. twl6030 is using a single level IRQ controller and thus does not require any trick. Move the irq_alloc_desc and irq_domain_add_legacy in twl4030-irq and twl6030-irq. Allocate together CORE and PWR IRQs for twl4030-irq. Conflicts: drivers/mfd/twl-core.c Signed-off-by: Benoit Cousson <b-cousson@ti.com> Acked-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Родитель
1b8f333ff4
Коммит
78518ffa08
|
@ -147,9 +147,6 @@
|
||||||
|
|
||||||
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
|
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
|
||||||
|
|
||||||
#define TWL4030_NR_IRQS 8
|
|
||||||
#define TWL6030_NR_IRQS 20
|
|
||||||
|
|
||||||
/* Base Address defns for twl4030_map[] */
|
/* Base Address defns for twl4030_map[] */
|
||||||
|
|
||||||
/* subchip/slave 0 - USB ID */
|
/* subchip/slave 0 - USB ID */
|
||||||
|
@ -1186,17 +1183,12 @@ static int __devinit
|
||||||
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int irq_base;
|
int irq_base;
|
||||||
int irq_end;
|
|
||||||
int status;
|
int status;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct twl4030_platform_data *pdata = client->dev.platform_data;
|
struct twl4030_platform_data *pdata = client->dev.platform_data;
|
||||||
struct device_node *node = client->dev.of_node;
|
struct device_node *node = client->dev.of_node;
|
||||||
u8 temp;
|
u8 temp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int nr_irqs = TWL4030_NR_IRQS;
|
|
||||||
|
|
||||||
if ((id->driver_data) & TWL6030_CLASS)
|
|
||||||
nr_irqs = TWL6030_NR_IRQS;
|
|
||||||
|
|
||||||
if (node && !pdata) {
|
if (node && !pdata) {
|
||||||
/*
|
/*
|
||||||
|
@ -1215,17 +1207,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = irq_alloc_descs(-1, 0, nr_irqs, 0);
|
|
||||||
if (IS_ERR_VALUE(status)) {
|
|
||||||
dev_err(&client->dev, "Fail to allocate IRQ descs\n");
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
irq_base = status;
|
|
||||||
irq_end = irq_base + nr_irqs;
|
|
||||||
irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
|
|
||||||
&irq_domain_simple_ops, NULL);
|
|
||||||
|
|
||||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
|
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
|
||||||
dev_dbg(&client->dev, "can't talk I2C?\n");
|
dev_dbg(&client->dev, "can't talk I2C?\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -1280,15 +1261,15 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
if (client->irq) {
|
if (client->irq) {
|
||||||
if (twl_class_is_4030()) {
|
if (twl_class_is_4030()) {
|
||||||
twl4030_init_chip_irq(id->name);
|
twl4030_init_chip_irq(id->name);
|
||||||
status = twl4030_init_irq(client->irq, irq_base,
|
irq_base = twl4030_init_irq(&client->dev, client->irq);
|
||||||
irq_end);
|
|
||||||
} else {
|
} else {
|
||||||
status = twl6030_init_irq(client->irq, irq_base,
|
irq_base = twl6030_init_irq(&client->dev, client->irq);
|
||||||
irq_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < 0)
|
if (irq_base < 0) {
|
||||||
|
status = irq_base;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
|
/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#ifndef __TWL_CORE_H__
|
#ifndef __TWL_CORE_H__
|
||||||
#define __TWL_CORE_H__
|
#define __TWL_CORE_H__
|
||||||
|
|
||||||
extern int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
|
extern int twl6030_init_irq(struct device *dev, int irq_num);
|
||||||
extern int twl6030_exit_irq(void);
|
extern int twl6030_exit_irq(void);
|
||||||
extern int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
|
extern int twl4030_init_irq(struct device *dev, int irq_num);
|
||||||
extern int twl4030_exit_irq(void);
|
extern int twl4030_exit_irq(void);
|
||||||
extern int twl4030_init_chip_irq(const char *chip);
|
extern int twl4030_init_chip_irq(const char *chip);
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/export.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/i2c/twl.h>
|
#include <linux/i2c/twl.h>
|
||||||
|
|
||||||
#include "twl-core.h"
|
#include "twl-core.h"
|
||||||
|
@ -53,6 +56,8 @@
|
||||||
* base + 8 .. base + 15 SIH for PWR_INT
|
* base + 8 .. base + 15 SIH for PWR_INT
|
||||||
* base + 16 .. base + 33 SIH for GPIO
|
* base + 16 .. base + 33 SIH for GPIO
|
||||||
*/
|
*/
|
||||||
|
#define TWL4030_CORE_NR_IRQS 8
|
||||||
|
#define TWL4030_PWR_NR_IRQS 8
|
||||||
|
|
||||||
/* PIH register offsets */
|
/* PIH register offsets */
|
||||||
#define REG_PIH_ISR_P1 0x01
|
#define REG_PIH_ISR_P1 0x01
|
||||||
|
@ -695,13 +700,33 @@ int twl4030_sih_setup(int module)
|
||||||
/* FIXME pass in which interrupt line we'll use ... */
|
/* FIXME pass in which interrupt line we'll use ... */
|
||||||
#define twl_irq_line 0
|
#define twl_irq_line 0
|
||||||
|
|
||||||
int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
int twl4030_init_irq(struct device *dev, int irq_num)
|
||||||
{
|
{
|
||||||
static struct irq_chip twl4030_irq_chip;
|
static struct irq_chip twl4030_irq_chip;
|
||||||
|
int irq_base, irq_end, nr_irqs;
|
||||||
|
struct device_node *node = dev->of_node;
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TWL core and pwr interrupts must be contiguous because
|
||||||
|
* the hwirqs numbers are defined contiguously from 1 to 15.
|
||||||
|
* Create only one domain for both.
|
||||||
|
*/
|
||||||
|
nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
|
||||||
|
|
||||||
|
irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
|
||||||
|
if (IS_ERR_VALUE(irq_base)) {
|
||||||
|
dev_err(dev, "Fail to allocate IRQ descs\n");
|
||||||
|
return irq_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
|
||||||
|
&irq_domain_simple_ops, NULL);
|
||||||
|
|
||||||
|
irq_end = irq_base + TWL4030_CORE_NR_IRQS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mask and clear all TWL4030 interrupts since initially we do
|
* Mask and clear all TWL4030 interrupts since initially we do
|
||||||
* not have any TWL4030 module interrupt handlers present
|
* not have any TWL4030 module interrupt handlers present
|
||||||
|
@ -747,7 +772,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
||||||
goto fail_rqirq;
|
goto fail_rqirq;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return irq_base;
|
||||||
fail_rqirq:
|
fail_rqirq:
|
||||||
/* clean up twl4030_sih_setup */
|
/* clean up twl4030_sih_setup */
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include <linux/i2c/twl.h>
|
#include <linux/i2c/twl.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
|
||||||
#include "twl-core.h"
|
#include "twl-core.h"
|
||||||
|
|
||||||
|
@ -53,6 +55,7 @@
|
||||||
* specifies mapping between interrupt number and the associated module.
|
* specifies mapping between interrupt number and the associated module.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#define TWL6030_NR_IRQS 20
|
||||||
|
|
||||||
static int twl6030_interrupt_mapping[24] = {
|
static int twl6030_interrupt_mapping[24] = {
|
||||||
PWR_INTR_OFFSET, /* Bit 0 PWRON */
|
PWR_INTR_OFFSET, /* Bit 0 PWRON */
|
||||||
|
@ -246,11 +249,6 @@ static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static unsigned twl6030_irq_next;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
|
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -350,8 +348,10 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(twl6030_mmc_card_detect);
|
EXPORT_SYMBOL(twl6030_mmc_card_detect);
|
||||||
|
|
||||||
int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
int twl6030_init_irq(struct device *dev, int irq_num)
|
||||||
{
|
{
|
||||||
|
struct device_node *node = dev->of_node;
|
||||||
|
int nr_irqs, irq_base, irq_end;
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
int i;
|
int i;
|
||||||
|
@ -360,6 +360,20 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
||||||
u8 mask[4];
|
u8 mask[4];
|
||||||
|
|
||||||
static struct irq_chip twl6030_irq_chip;
|
static struct irq_chip twl6030_irq_chip;
|
||||||
|
|
||||||
|
nr_irqs = TWL6030_NR_IRQS;
|
||||||
|
|
||||||
|
irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
|
||||||
|
if (IS_ERR_VALUE(irq_base)) {
|
||||||
|
dev_err(dev, "Fail to allocate IRQ descs\n");
|
||||||
|
return irq_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
|
||||||
|
&irq_domain_simple_ops, NULL);
|
||||||
|
|
||||||
|
irq_end = irq_base + nr_irqs;
|
||||||
|
|
||||||
mask[1] = 0xFF;
|
mask[1] = 0xFF;
|
||||||
mask[2] = 0xFF;
|
mask[2] = 0xFF;
|
||||||
mask[3] = 0xFF;
|
mask[3] = 0xFF;
|
||||||
|
@ -387,9 +401,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
||||||
activate_irq(i);
|
activate_irq(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
twl6030_irq_next = i;
|
|
||||||
pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
|
pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
|
||||||
irq_num, irq_base, twl6030_irq_next - 1);
|
irq_num, irq_base, irq_end);
|
||||||
|
|
||||||
/* install an irq handler to demultiplex the TWL6030 interrupt */
|
/* install an irq handler to demultiplex the TWL6030 interrupt */
|
||||||
init_completion(&irq_event);
|
init_completion(&irq_event);
|
||||||
|
@ -410,7 +423,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
|
||||||
|
|
||||||
twl_irq = irq_num;
|
twl_irq = irq_num;
|
||||||
register_pm_notifier(&twl6030_irq_pm_notifier_block);
|
register_pm_notifier(&twl6030_irq_pm_notifier_block);
|
||||||
return status;
|
return irq_base;
|
||||||
|
|
||||||
fail_kthread:
|
fail_kthread:
|
||||||
free_irq(irq_num, &irq_event);
|
free_irq(irq_num, &irq_event);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче