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

Commit 2ced445e authored by Linus Walleij's avatar Linus Walleij Committed by Samuel Ortiz
Browse files

mfd: Parametrize ab8500 IRQ masks and registers



This makes the AB8500 state struct contain the IRQ mask and
register offsets previously hard-coded so as to make room for
more AB8500 variants.

Reviewed-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarMaxime Coquelin <maxime.coquelin@stericsson.com>
Signed-off-by: default avatarAlex Macro <alex.macro@stericsson.com>
Signed-off-by: default avatarMichel Jaouen <michel.jaouen@stericsson.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 0f620837
Loading
Loading
Loading
Loading
+37 −13
Original line number Diff line number Diff line
@@ -97,11 +97,13 @@

/*
 * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
 * numbers are indexed into this array with (num / 8).
 * numbers are indexed into this array with (num / 8). The interupts are
 * defined in linux/mfd/ab8500.h
 *
 * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
 * offset 0.
 */
/* AB8500 support */
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
@@ -256,7 +258,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
	int i;

	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
	for (i = 0; i < ab8500->mask_size; i++) {
		u8 old = ab8500->oldmask[i];
		u8 new = ab8500->mask[i];
		int reg;
@@ -274,7 +276,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)

		ab8500->oldmask[i] = new;

		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
	}

@@ -317,8 +319,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)

	dev_vdbg(ab8500->dev, "interrupt\n");

	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
		int regoffset = ab8500_irq_regoffset[i];
	for (i = 0; i < ab8500->mask_size; i++) {
		int regoffset = ab8500->irq_reg_offset[i];
		int status;
		u8 value;

@@ -350,8 +352,11 @@ static int ab8500_irq_init(struct ab8500 *ab8500)
{
	int base = ab8500->irq_base;
	int irq;
	int num_irqs;

	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
	num_irqs = AB8500_NR_IRQS;

	for (irq = base; irq < base + num_irqs; irq++) {
		irq_set_chip_data(irq, ab8500);
		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
					 handle_simple_irq);
@@ -370,8 +375,11 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
{
	int base = ab8500->irq_base;
	int irq;
	int num_irqs;

	num_irqs = AB8500_NR_IRQS;

	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
	for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM
		set_irq_flags(irq, 0);
#endif
@@ -907,6 +915,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
			ab8500->chip_id >> 4,
			ab8500->chip_id & 0x0F);

	ab8500->mask_size = AB8500_NUM_IRQ_REGS;
	ab8500->irq_reg_offset = ab8500_irq_regoffset;
	ab8500->mask = kzalloc(ab8500->mask_size, GFP_KERNEL);
	if (!ab8500->mask)
		return -ENOMEM;
	ab8500->oldmask = kzalloc(ab8500->mask_size, GFP_KERNEL);
	if (!ab8500->oldmask) {
		ret = -ENOMEM;
		goto out_freemask;
	}
	/*
	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
	 * 0x01 Swoff bit programming
@@ -929,7 +947,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
		plat->init(ab8500);

	/* Clear and mask all interrupts */
	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
	for (i = 0; i < ab8500->mask_size; i++) {
		/*
		 * Interrupt register 12 doesn't exist prior to AB8500 version
		 * 2.0
@@ -939,23 +957,23 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
			continue;

		get_register_interruptible(ab8500, AB8500_INTERRUPT,
			AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
			&value);
		set_register_interruptible(ab8500, AB8500_INTERRUPT,
			AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
			AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i], 0xff);
	}

	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
	if (ret)
		return ret;
		goto out_freeoldmask;

	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
	for (i = 0; i < ab8500->mask_size; i++)
		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;

	if (ab8500->irq_base) {
		ret = ab8500_irq_init(ab8500);
		if (ret)
			return ret;
			goto out_freeoldmask;

		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
					   IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -982,6 +1000,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
out_removeirq:
	if (ab8500->irq_base)
		ab8500_irq_remove(ab8500);
out_freeoldmask:
	kfree(ab8500->oldmask);
out_freemask:
	kfree(ab8500->mask);

	return ret;
}
@@ -994,6 +1016,8 @@ int __devexit ab8500_exit(struct ab8500 *ab8500)
		free_irq(ab8500->irq, ab8500);
		ab8500_irq_remove(ab8500);
	}
	kfree(ab8500->oldmask);
	kfree(ab8500->mask);

	return 0;
}
+7 −2
Original line number Diff line number Diff line
@@ -175,6 +175,9 @@ enum ab8500_version {
 * @tx_buf: tx buf for SPI
 * @mask: cache of IRQ regs for bus lock
 * @oldmask: cache of previous IRQ regs for bus lock
 * @mask_size: Actual number of valid entries in mask[], oldmask[] and
 * irq_reg_offset
 * @irq_reg_offset: Array of offsets into IRQ registers
 */
struct ab8500 {
	struct device	*dev;
@@ -192,8 +195,10 @@ struct ab8500 {
	unsigned long	tx_buf[4];
	unsigned long	rx_buf[4];

	u8 mask[AB8500_NUM_IRQ_REGS];
	u8 oldmask[AB8500_NUM_IRQ_REGS];
	u8 *mask;
	u8 *oldmask;
	int mask_size;
	const int *irq_reg_offset;
};

struct regulator_reg_init;