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

Commit ab7edb14 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Samuel Ortiz
Browse files

mfd: twl6040: Convert to use regmap_irq



With regmap_irq it is possible to remove the twl6040-irq.c file and
simplify the code.

Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Reviewed-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 1ac96265
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -321,10 +321,10 @@ config MFD_TWL4030_AUDIO

config TWL6040_CORE
	bool "Support for TWL6040 audio codec"
	depends on I2C=y && GENERIC_HARDIRQS
	depends on I2C=y
	select MFD_CORE
	select REGMAP_I2C
	select IRQ_DOMAIN
	select REGMAP_IRQ
	default n
	help
	  Say yes here if you want support for Texas Instruments TWL6040 audio
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
obj-$(CONFIG_TWL4030_MADC)      += twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO)	+= twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE)	+= twl6040-core.o twl6040-irq.o
obj-$(CONFIG_TWL6040_CORE)	+= twl6040-core.o

obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI)	+= mc13xxx-spi.o
+40 −15
Original line number Diff line number Diff line
@@ -499,6 +499,25 @@ static struct regmap_config twl6040_regmap_config = {
	.readable_reg = twl6040_readable_reg,
};

static const struct regmap_irq twl6040_irqs[] = {
	{ .reg_offset = 0, .mask = TWL6040_THINT, },
	{ .reg_offset = 0, .mask = TWL6040_PLUGINT | TWL6040_UNPLUGINT, },
	{ .reg_offset = 0, .mask = TWL6040_HOOKINT, },
	{ .reg_offset = 0, .mask = TWL6040_HFINT, },
	{ .reg_offset = 0, .mask = TWL6040_VIBINT, },
	{ .reg_offset = 0, .mask = TWL6040_READYINT, },
};

static struct regmap_irq_chip twl6040_irq_chip = {
	.name = "twl6040",
	.irqs = twl6040_irqs,
	.num_irqs = ARRAY_SIZE(twl6040_irqs),

	.num_regs = 1,
	.status_base = TWL6040_REG_INTID,
	.mask_base = TWL6040_REG_INTMR,
};

static int __devinit twl6040_probe(struct i2c_client *client,
				     const struct i2c_device_id *id)
{
@@ -574,21 +593,27 @@ static int __devinit twl6040_probe(struct i2c_client *client,
			goto gpio_err;
	}

	/* codec interrupt */
	ret = twl6040_irq_init(twl6040);
	if (ret)
	ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq,
			IRQF_ONESHOT, 0, &twl6040_irq_chip,
			&twl6040->irq_data);
	if (ret < 0)
		goto irq_init_err;

	ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY,
				   NULL, twl6040_readyint_handler, IRQF_ONESHOT,
	twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data,
					       TWL6040_IRQ_READY);
	twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data,
					       TWL6040_IRQ_TH);

	ret = request_threaded_irq(twl6040->irq_ready, NULL,
				   twl6040_readyint_handler, IRQF_ONESHOT,
				   "twl6040_irq_ready", twl6040);
	if (ret) {
		dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret);
		goto readyirq_err;
	}

	ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_TH,
				   NULL, twl6040_thint_handler, IRQF_ONESHOT,
	ret = request_threaded_irq(twl6040->irq_th, NULL,
				   twl6040_thint_handler, IRQF_ONESHOT,
				   "twl6040_irq_th", twl6040);
	if (ret) {
		dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret);
@@ -604,7 +629,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
	 * The ASoC codec can work without pdata, pass the platform_data only if
	 * it has been provided.
	 */
	irq = twl6040->irq_base + TWL6040_IRQ_PLUG;
	irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG);
	cell = &twl6040->cells[children];
	cell->name = "twl6040-codec";
	twl6040_codec_rsrc[0].start = irq;
@@ -618,7 +643,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
	children++;

	if (twl6040_has_vibra(pdata, node)) {
		irq = twl6040->irq_base + TWL6040_IRQ_VIB;
		irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB);

		cell = &twl6040->cells[children];
		cell->name = "twl6040-vibra";
@@ -657,11 +682,11 @@ static int __devinit twl6040_probe(struct i2c_client *client,
	return 0;

mfd_err:
	free_irq(twl6040->irq_base + TWL6040_IRQ_TH, twl6040);
	free_irq(twl6040->irq_th, twl6040);
thirq_err:
	free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
	free_irq(twl6040->irq_ready, twl6040);
readyirq_err:
	twl6040_irq_exit(twl6040);
	regmap_del_irq_chip(twl6040->irq, twl6040->irq_data);
irq_init_err:
	if (gpio_is_valid(twl6040->audpwron))
		gpio_free(twl6040->audpwron);
@@ -685,9 +710,9 @@ static int __devexit twl6040_remove(struct i2c_client *client)
	if (gpio_is_valid(twl6040->audpwron))
		gpio_free(twl6040->audpwron);

	free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040);
	free_irq(twl6040->irq_base + TWL6040_IRQ_TH, twl6040);
	twl6040_irq_exit(twl6040);
	free_irq(twl6040->irq_ready, twl6040);
	free_irq(twl6040->irq_th, twl6040);
	regmap_del_irq_chip(twl6040->irq, twl6040->irq_data);

	mfd_remove_devices(&client->dev);
	i2c_set_clientdata(client, NULL);

drivers/mfd/twl6040-irq.c

deleted100644 → 0
+0 −205
Original line number Diff line number Diff line
/*
 * Interrupt controller support for TWL6040
 *
 * Author:     Misael Lopez Cruz <misael.lopez@ti.com>
 *
 * Copyright:   (C) 2011 Texas Instruments, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/twl6040.h>

struct twl6040_irq_data {
	int mask;
	int status;
};

static struct twl6040_irq_data twl6040_irqs[] = {
	{
		.mask = TWL6040_THMSK,
		.status = TWL6040_THINT,
	},
	{
		.mask = TWL6040_PLUGMSK,
		.status = TWL6040_PLUGINT | TWL6040_UNPLUGINT,
	},
	{
		.mask = TWL6040_HOOKMSK,
		.status = TWL6040_HOOKINT,
	},
	{
		.mask = TWL6040_HFMSK,
		.status = TWL6040_HFINT,
	},
	{
		.mask = TWL6040_VIBMSK,
		.status = TWL6040_VIBINT,
	},
	{
		.mask = TWL6040_READYMSK,
		.status = TWL6040_READYINT,
	},
};

static inline
struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040,
					    int irq)
{
	return &twl6040_irqs[irq - twl6040->irq_base];
}

static void twl6040_irq_lock(struct irq_data *data)
{
	struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);

	mutex_lock(&twl6040->irq_mutex);
}

static void twl6040_irq_sync_unlock(struct irq_data *data)
{
	struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);

	/* write back to hardware any change in irq mask */
	if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) {
		twl6040->irq_masks_cache = twl6040->irq_masks_cur;
		twl6040_reg_write(twl6040, TWL6040_REG_INTMR,
				  twl6040->irq_masks_cur);
	}

	mutex_unlock(&twl6040->irq_mutex);
}

static void twl6040_irq_enable(struct irq_data *data)
{
	struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
	struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
							       data->irq);

	twl6040->irq_masks_cur &= ~irq_data->mask;
}

static void twl6040_irq_disable(struct irq_data *data)
{
	struct twl6040 *twl6040 = irq_data_get_irq_chip_data(data);
	struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040,
							       data->irq);

	twl6040->irq_masks_cur |= irq_data->mask;
}

static struct irq_chip twl6040_irq_chip = {
	.name			= "twl6040",
	.irq_bus_lock		= twl6040_irq_lock,
	.irq_bus_sync_unlock	= twl6040_irq_sync_unlock,
	.irq_enable		= twl6040_irq_enable,
	.irq_disable		= twl6040_irq_disable,
};

static irqreturn_t twl6040_irq_thread(int irq, void *data)
{
	struct twl6040 *twl6040 = data;
	u8 intid;
	int i;

	intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);

	/* apply masking and report (backwards to handle READYINT first) */
	for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) {
		if (twl6040->irq_masks_cur & twl6040_irqs[i].mask)
			intid &= ~twl6040_irqs[i].status;
		if (intid & twl6040_irqs[i].status)
			handle_nested_irq(twl6040->irq_base + i);
	}

	/* ack unmasked irqs */
	twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid);

	return IRQ_HANDLED;
}

int twl6040_irq_init(struct twl6040 *twl6040)
{
	struct device_node *node = twl6040->dev->of_node;
	int i, nr_irqs, irq_base, ret;
	u8 val;

	mutex_init(&twl6040->irq_mutex);

	/* mask the individual interrupt sources */
	twl6040->irq_masks_cur = TWL6040_ALLINT_MSK;
	twl6040->irq_masks_cache = TWL6040_ALLINT_MSK;
	twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);

	nr_irqs = ARRAY_SIZE(twl6040_irqs);

	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
	if (IS_ERR_VALUE(irq_base)) {
		dev_err(twl6040->dev, "Fail to allocate IRQ descs\n");
		return irq_base;
	}
	twl6040->irq_base = irq_base;

	irq_domain_add_legacy(node, ARRAY_SIZE(twl6040_irqs), irq_base, 0,
			      &irq_domain_simple_ops, NULL);

	/* Register them with genirq */
	for (i = irq_base; i < irq_base + nr_irqs; i++) {
		irq_set_chip_data(i, twl6040);
		irq_set_chip_and_handler(i, &twl6040_irq_chip,
					 handle_level_irq);
		irq_set_nested_thread(i, 1);

		/* ARM needs us to explicitly flag the IRQ as valid
		 * and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
		set_irq_flags(i, IRQF_VALID);
#else
		irq_set_noprobe(i);
#endif
	}

	ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread,
				   IRQF_ONESHOT, "twl6040", twl6040);
	if (ret) {
		dev_err(twl6040->dev, "failed to request IRQ %d: %d\n",
			twl6040->irq, ret);
		return ret;
	}

	/* reset interrupts */
	val = twl6040_reg_read(twl6040, TWL6040_REG_INTID);

	/* interrupts cleared on write */
	twl6040_clear_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_INTCLRMODE);

	return 0;
}
EXPORT_SYMBOL(twl6040_irq_init);

void twl6040_irq_exit(struct twl6040 *twl6040)
{
	free_irq(twl6040->irq, twl6040);
}
EXPORT_SYMBOL(twl6040_irq_exit);
+5 −5
Original line number Diff line number Diff line
@@ -207,10 +207,12 @@ struct twl6040_platform_data {
};

struct regmap;
struct regmap_irq_chips_data;

struct twl6040 {
	struct device *dev;
	struct regmap *regmap;
	struct regmap_irq_chip_data *irq_data;
	struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */
	struct mutex mutex;
	struct mutex irq_mutex;
@@ -228,9 +230,8 @@ struct twl6040 {
	unsigned int mclk;

	unsigned int irq;
	unsigned int irq_base;
	u8 irq_masks_cur;
	u8 irq_masks_cache;
	unsigned int irq_ready;
	unsigned int irq_th;
};

int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg);
@@ -245,8 +246,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
		    unsigned int freq_in, unsigned int freq_out);
int twl6040_get_pll(struct twl6040 *twl6040);
unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
int twl6040_irq_init(struct twl6040 *twl6040);
void twl6040_irq_exit(struct twl6040 *twl6040);

/* Get the combined status of the vibra control register */
int twl6040_get_vibralr_status(struct twl6040 *twl6040);