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: Peter Ujfalusi <peter.ujfalusi@ti.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Родитель
1ac96265a6
Коммит
ab7edb149c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* 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);
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче