Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78518ffa authored by Benoit Cousson's avatar Benoit Cousson Committed by Samuel Ortiz
Browse files

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: default avatarBenoit Cousson <b-cousson@ti.com>
Acked-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 1b8f333f
Loading
Loading
Loading
Loading
+5 −24
Original line number Original line Diff line number Diff line
@@ -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,16 +1261,16 @@ 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.
	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
+2 −2
Original line number Original line Diff line number Diff line
#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);


+27 −2
Original line number Original line Diff line number Diff line
@@ -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:
+22 −9
Original line number Original line Diff line number Diff line
@@ -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);