mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (526 commits)
ASoC: twl6040 - Add method to query optimum PDM_DL1 gain
ALSA: hda - Fix the lost power-setup of seconary pins after PM resume
ALSA: usb-audio: add Yamaha MOX6/MOX8 support
ALSA: virtuoso: add S/PDIF input support for all Xonars
ALSA: ice1724 - Support for ooAoo SQ210a
ALSA: ice1724 - Allow card info based on model only
ALSA: ice1724 - Create capture pcm only for ADC-enabled configurations
ALSA: hdspm - Provide unique driver id based on card serial
ASoC: Dynamically allocate the rtd device for a non-empty release()
ASoC: Fix recursive dependency due to select ATMEL_SSC in SND_ATMEL_SOC_SSC
ALSA: hda - Fix the detection of "Loopback Mixing" control for VIA codecs
ALSA: hda - Return the error from get_wcaps_type() for invalid NIDs
ALSA: hda - Use auto-parser for HP laptops with cx20459 codec
ALSA: asihpi - Fix potential Oops in snd_asihpi_cmode_info()
ALSA: hdsp - Fix potential Oops in snd_hdsp_info_pref_sync_ref()
ALSA: hda/cirrus - support for iMac12,2 model
ASoC: cx20442: add bias control over a platform provided regulator
ALSA: usb-audio - Avoid flood of frame-active debug messages
ALSA: snd-usb-us122l: Delete calls to preempt_disable
mfd: Put WM8994 into cache only mode when suspending
...
Fix up trivial conflicts in:
- arch/arm/mach-s3c64xx/mach-crag6410.c:
renamed speyside_wm8962 to tobermory, added littlemill right
next to it
- drivers/base/regmap/{regcache.c,regmap.c}:
duplicate diff that had already come in with other changes in
the regmap tree
This commit is contained in:
commit
a429638cac
510 changed files with 17132 additions and 16566 deletions
|
|
@ -505,6 +505,7 @@ config MFD_WM8994
|
|||
bool "Support Wolfson Microelectronics WM8994"
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
The WM8994 is a highly integrated hi-fi CODEC designed for
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
|
|||
wm8350-objs += wm8350-irq.o
|
||||
obj-$(CONFIG_MFD_WM8350) += wm8350.o
|
||||
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
|
||||
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
|
||||
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
|
||||
|
||||
obj-$(CONFIG_TPS6105X) += tps6105x.o
|
||||
obj-$(CONFIG_TPS65010) += tps65010.o
|
||||
|
|
|
|||
|
|
@ -28,11 +28,7 @@
|
|||
#include <linux/mfd/wm8994/pdata.h>
|
||||
#include <linux/mfd/wm8994/registers.h>
|
||||
|
||||
static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
|
||||
int bytes, void *dest)
|
||||
{
|
||||
return regmap_raw_read(wm8994->regmap, reg, dest, bytes);
|
||||
}
|
||||
#include "wm8994.h"
|
||||
|
||||
/**
|
||||
* wm8994_reg_read: Read a single WM8994 register.
|
||||
|
|
@ -68,12 +64,6 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
|
|||
return regmap_bulk_read(wm8994->regmap, reg, buf, count);
|
||||
}
|
||||
|
||||
static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
|
||||
int bytes, const void *src)
|
||||
{
|
||||
return regmap_raw_write(wm8994->regmap, reg, src, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* wm8994_reg_write: Write a single WM8994 register.
|
||||
*
|
||||
|
|
@ -252,6 +242,20 @@ static int wm8994_suspend(struct device *dev)
|
|||
break;
|
||||
}
|
||||
|
||||
switch (wm8994->type) {
|
||||
case WM1811:
|
||||
ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read jackdet: %d\n", ret);
|
||||
} else if (ret & WM1811_JACKDET_MODE_MASK) {
|
||||
dev_dbg(dev, "CODEC still active, ignoring suspend\n");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable LDO pulldowns while the device is suspended if we
|
||||
* don't know that something will be driving them. */
|
||||
if (!wm8994->ldo_ena_always_driven)
|
||||
|
|
@ -259,25 +263,14 @@ static int wm8994_suspend(struct device *dev)
|
|||
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
|
||||
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
|
||||
|
||||
/* GPIO configuration state is saved here since we may be configuring
|
||||
* the GPIO alternate functions even if we're not using the gpiolib
|
||||
* driver for them.
|
||||
*/
|
||||
ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
|
||||
&wm8994->gpio_regs);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to save GPIO registers: %d\n", ret);
|
||||
|
||||
/* For similar reasons we also stash the regulator states */
|
||||
ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
|
||||
&wm8994->ldo_regs);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to save LDO registers: %d\n", ret);
|
||||
|
||||
/* Explicitly put the device into reset in case regulators
|
||||
* don't get disabled in order to ensure consistent restart.
|
||||
*/
|
||||
wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994);
|
||||
wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
|
||||
wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
|
||||
|
||||
regcache_cache_only(wm8994->regmap, true);
|
||||
regcache_mark_dirty(wm8994->regmap);
|
||||
|
||||
wm8994->suspended = true;
|
||||
|
||||
|
|
@ -294,7 +287,7 @@ static int wm8994_suspend(struct device *dev)
|
|||
static int wm8994_resume(struct device *dev)
|
||||
{
|
||||
struct wm8994 *wm8994 = dev_get_drvdata(dev);
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
/* We may have lied to the PM core about suspending */
|
||||
if (!wm8994->suspended)
|
||||
|
|
@ -307,27 +300,13 @@ static int wm8994_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Write register at a time as we use the cache on the CPU so store
|
||||
* it in native endian.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
|
||||
ret = wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK
|
||||
+ i, wm8994->irq_masks_cur[i]);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to restore interrupt masks: %d\n",
|
||||
ret);
|
||||
regcache_cache_only(wm8994->regmap, false);
|
||||
ret = regcache_sync(wm8994->regmap);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to restore register map: %d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
|
||||
&wm8994->ldo_regs);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to restore LDO registers: %d\n", ret);
|
||||
|
||||
ret = wm8994_write(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
|
||||
&wm8994->gpio_regs);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
|
||||
|
||||
/* Disable LDO pulldowns while the device is active */
|
||||
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
|
||||
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
|
||||
|
|
@ -336,6 +315,11 @@ static int wm8994_resume(struct device *dev)
|
|||
wm8994->suspended = false;
|
||||
|
||||
return 0;
|
||||
|
||||
err_enable:
|
||||
regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -361,19 +345,16 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct regmap_config wm8994_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate the generic non-control parts of the device.
|
||||
*/
|
||||
static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
||||
{
|
||||
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
|
||||
struct regmap_config *regmap_config;
|
||||
const char *devname;
|
||||
int ret, i;
|
||||
int pulls = 0;
|
||||
|
||||
dev_set_drvdata(wm8994->dev, wm8994);
|
||||
|
||||
|
|
@ -402,9 +383,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
|||
goto err_regmap;
|
||||
}
|
||||
|
||||
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
|
||||
wm8994->num_supplies,
|
||||
GFP_KERNEL);
|
||||
wm8994->supplies = devm_kzalloc(wm8994->dev,
|
||||
sizeof(struct regulator_bulk_data) *
|
||||
wm8994->num_supplies, GFP_KERNEL);
|
||||
if (!wm8994->supplies) {
|
||||
ret = -ENOMEM;
|
||||
goto err_regmap;
|
||||
|
|
@ -432,7 +413,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
|||
wm8994->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
|
||||
goto err_supplies;
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(wm8994->num_supplies,
|
||||
|
|
@ -482,25 +463,54 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
|||
ret);
|
||||
goto err_enable;
|
||||
}
|
||||
wm8994->revision = ret;
|
||||
|
||||
switch (wm8994->type) {
|
||||
case WM8994:
|
||||
switch (ret) {
|
||||
switch (wm8994->revision) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_warn(wm8994->dev,
|
||||
"revision %c not fully supported\n",
|
||||
'A' + ret);
|
||||
'A' + wm8994->revision);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM1811:
|
||||
/* Revision C did not change the relevant layer */
|
||||
if (wm8994->revision > 1)
|
||||
wm8994->revision++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
|
||||
dev_info(wm8994->dev, "%s revision %c\n", devname,
|
||||
'A' + wm8994->revision);
|
||||
|
||||
switch (wm8994->type) {
|
||||
case WM1811:
|
||||
regmap_config = &wm1811_regmap_config;
|
||||
break;
|
||||
case WM8994:
|
||||
regmap_config = &wm8994_regmap_config;
|
||||
break;
|
||||
case WM8958:
|
||||
regmap_config = &wm8958_regmap_config;
|
||||
break;
|
||||
default:
|
||||
dev_err(wm8994->dev, "Unknown device type %d\n", wm8994->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_reinit_cache(wm8994->regmap, regmap_config);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to reinit register cache: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
wm8994->irq_base = pdata->irq_base;
|
||||
|
|
@ -516,12 +526,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
|
|||
}
|
||||
|
||||
wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
|
||||
|
||||
if (pdata->spkmode_pu)
|
||||
pulls |= WM8994_SPKMODE_PU;
|
||||
}
|
||||
|
||||
/* Disable LDO pulldowns while the device is active */
|
||||
/* Disable unneeded pulls */
|
||||
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
|
||||
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
|
||||
0);
|
||||
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD |
|
||||
WM8994_SPKMODE_PU | WM8994_CSNADDR_PD,
|
||||
pulls);
|
||||
|
||||
/* In some system designs where the regulators are not in use,
|
||||
* we can achieve a small reduction in leakage currents by
|
||||
|
|
@ -560,12 +574,9 @@ err_enable:
|
|||
wm8994->supplies);
|
||||
err_get:
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
err_supplies:
|
||||
kfree(wm8994->supplies);
|
||||
err_regmap:
|
||||
regmap_exit(wm8994->regmap);
|
||||
mfd_remove_devices(wm8994->dev);
|
||||
kfree(wm8994);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -577,18 +588,24 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
|
|||
regulator_bulk_disable(wm8994->num_supplies,
|
||||
wm8994->supplies);
|
||||
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
|
||||
kfree(wm8994->supplies);
|
||||
regmap_exit(wm8994->regmap);
|
||||
kfree(wm8994);
|
||||
}
|
||||
|
||||
static const struct of_device_id wm8994_of_match[] = {
|
||||
{ .compatible = "wlf,wm1811", },
|
||||
{ .compatible = "wlf,wm8994", },
|
||||
{ .compatible = "wlf,wm8958", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8994_of_match);
|
||||
|
||||
static int wm8994_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8994 *wm8994;
|
||||
int ret;
|
||||
|
||||
wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
|
||||
wm8994 = devm_kzalloc(&i2c->dev, sizeof(struct wm8994), GFP_KERNEL);
|
||||
if (wm8994 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -597,12 +614,11 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
|
|||
wm8994->irq = i2c->irq;
|
||||
wm8994->type = id->driver_data;
|
||||
|
||||
wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config);
|
||||
wm8994->regmap = regmap_init_i2c(i2c, &wm8994_base_regmap_config);
|
||||
if (IS_ERR(wm8994->regmap)) {
|
||||
ret = PTR_ERR(wm8994->regmap);
|
||||
dev_err(wm8994->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
kfree(wm8994);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -620,6 +636,7 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
|
|||
|
||||
static const struct i2c_device_id wm8994_i2c_id[] = {
|
||||
{ "wm1811", WM1811 },
|
||||
{ "wm1811a", WM1811 },
|
||||
{ "wm8994", WM8994 },
|
||||
{ "wm8958", WM8958 },
|
||||
{ }
|
||||
|
|
@ -634,6 +651,7 @@ static struct i2c_driver wm8994_i2c_driver = {
|
|||
.name = "wm8994",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &wm8994_pm_ops,
|
||||
.of_match_table = wm8994_of_match,
|
||||
},
|
||||
.probe = wm8994_i2c_probe,
|
||||
.remove = wm8994_i2c_remove,
|
||||
|
|
|
|||
|
|
@ -18,248 +18,127 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/wm8994/core.h>
|
||||
#include <linux/mfd/wm8994/registers.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
struct wm8994_irq_data {
|
||||
int reg;
|
||||
int mask;
|
||||
};
|
||||
|
||||
static struct wm8994_irq_data wm8994_irqs[] = {
|
||||
static struct regmap_irq wm8994_irqs[] = {
|
||||
[WM8994_IRQ_TEMP_SHUT] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_TEMP_SHUT_EINT,
|
||||
},
|
||||
[WM8994_IRQ_MIC1_DET] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_MIC1_DET_EINT,
|
||||
},
|
||||
[WM8994_IRQ_MIC1_SHRT] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_MIC1_SHRT_EINT,
|
||||
},
|
||||
[WM8994_IRQ_MIC2_DET] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_MIC2_DET_EINT,
|
||||
},
|
||||
[WM8994_IRQ_MIC2_SHRT] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_MIC2_SHRT_EINT,
|
||||
},
|
||||
[WM8994_IRQ_FLL1_LOCK] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_FLL1_LOCK_EINT,
|
||||
},
|
||||
[WM8994_IRQ_FLL2_LOCK] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_FLL2_LOCK_EINT,
|
||||
},
|
||||
[WM8994_IRQ_SRC1_LOCK] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_SRC1_LOCK_EINT,
|
||||
},
|
||||
[WM8994_IRQ_SRC2_LOCK] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_SRC2_LOCK_EINT,
|
||||
},
|
||||
[WM8994_IRQ_AIF1DRC1_SIG_DET] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_AIF1DRC1_SIG_DET,
|
||||
},
|
||||
[WM8994_IRQ_AIF1DRC2_SIG_DET] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_AIF1DRC2_SIG_DET_EINT,
|
||||
},
|
||||
[WM8994_IRQ_AIF2DRC_SIG_DET] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_AIF2DRC_SIG_DET_EINT,
|
||||
},
|
||||
[WM8994_IRQ_FIFOS_ERR] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_FIFOS_ERR_EINT,
|
||||
},
|
||||
[WM8994_IRQ_WSEQ_DONE] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_WSEQ_DONE_EINT,
|
||||
},
|
||||
[WM8994_IRQ_DCS_DONE] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_DCS_DONE_EINT,
|
||||
},
|
||||
[WM8994_IRQ_TEMP_WARN] = {
|
||||
.reg = 2,
|
||||
.reg_offset = 1,
|
||||
.mask = WM8994_TEMP_WARN_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(1)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP1_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(2)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP2_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(3)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP3_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(4)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP4_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(5)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP5_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(6)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP6_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(7)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP7_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(8)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP8_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(9)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP8_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(10)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP10_EINT,
|
||||
},
|
||||
[WM8994_IRQ_GPIO(11)] = {
|
||||
.reg = 1,
|
||||
.mask = WM8994_GP11_EINT,
|
||||
},
|
||||
};
|
||||
|
||||
static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data)
|
||||
{
|
||||
return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
|
||||
}
|
||||
static struct regmap_irq_chip wm8994_irq_chip = {
|
||||
.name = "wm8994",
|
||||
.irqs = wm8994_irqs,
|
||||
.num_irqs = ARRAY_SIZE(wm8994_irqs),
|
||||
|
||||
static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data)
|
||||
{
|
||||
return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
|
||||
}
|
||||
|
||||
static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
|
||||
int irq)
|
||||
{
|
||||
return &wm8994_irqs[irq - wm8994->irq_base];
|
||||
}
|
||||
|
||||
static void wm8994_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&wm8994->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8994_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
|
||||
/* If there's been a change in the mask write it back
|
||||
* to the hardware. */
|
||||
if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
|
||||
wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
|
||||
wm8994_reg_write(wm8994,
|
||||
WM8994_INTERRUPT_STATUS_1_MASK + i,
|
||||
wm8994->irq_masks_cur[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&wm8994->irq_lock);
|
||||
}
|
||||
|
||||
static void wm8994_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
data->irq);
|
||||
|
||||
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void wm8994_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
|
||||
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
|
||||
data->irq);
|
||||
|
||||
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip wm8994_irq_chip = {
|
||||
.name = "wm8994",
|
||||
.irq_bus_lock = wm8994_irq_lock,
|
||||
.irq_bus_sync_unlock = wm8994_irq_sync_unlock,
|
||||
.irq_disable = wm8994_irq_disable,
|
||||
.irq_enable = wm8994_irq_enable,
|
||||
.num_regs = 2,
|
||||
.status_base = WM8994_INTERRUPT_STATUS_1,
|
||||
.mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
|
||||
.ack_base = WM8994_INTERRUPT_STATUS_1,
|
||||
};
|
||||
|
||||
/* The processing of the primary interrupt occurs in a thread so that
|
||||
* we can interact with the device over I2C or SPI. */
|
||||
static irqreturn_t wm8994_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct wm8994 *wm8994 = data;
|
||||
unsigned int i;
|
||||
u16 status[WM8994_NUM_IRQ_REGS];
|
||||
int ret;
|
||||
|
||||
ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
|
||||
WM8994_NUM_IRQ_REGS, status);
|
||||
if (ret < 0) {
|
||||
dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
|
||||
ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Bit swap and apply masking */
|
||||
for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
|
||||
status[i] = be16_to_cpu(status[i]);
|
||||
status[i] &= ~wm8994->irq_masks_cur[i];
|
||||
}
|
||||
|
||||
/* Ack any unmasked IRQs */
|
||||
for (i = 0; i < ARRAY_SIZE(status); i++) {
|
||||
if (status[i])
|
||||
wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
|
||||
status[i]);
|
||||
}
|
||||
|
||||
/* Report */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
|
||||
if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
|
||||
handle_nested_irq(wm8994->irq_base + i);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int wm8994_irq_init(struct wm8994 *wm8994)
|
||||
{
|
||||
int i, cur_irq, ret;
|
||||
|
||||
mutex_init(&wm8994->irq_lock);
|
||||
|
||||
/* Mask the individual interrupt sources */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
|
||||
wm8994->irq_masks_cur[i] = 0xffff;
|
||||
wm8994->irq_masks_cache[i] = 0xffff;
|
||||
wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
|
||||
0xffff);
|
||||
}
|
||||
int ret;
|
||||
|
||||
if (!wm8994->irq) {
|
||||
dev_warn(wm8994->dev,
|
||||
|
|
@ -274,30 +153,12 @@ int wm8994_irq_init(struct wm8994 *wm8994)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Register them with genirq */
|
||||
for (cur_irq = wm8994->irq_base;
|
||||
cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base;
|
||||
cur_irq++) {
|
||||
irq_set_chip_data(cur_irq, wm8994);
|
||||
irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip,
|
||||
handle_edge_irq);
|
||||
irq_set_nested_thread(cur_irq, 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(cur_irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(cur_irq);
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
"wm8994", wm8994);
|
||||
ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
wm8994->irq_base, &wm8994_irq_chip,
|
||||
&wm8994->irq_data);
|
||||
if (ret != 0) {
|
||||
dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n",
|
||||
wm8994->irq, ret);
|
||||
dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +170,5 @@ int wm8994_irq_init(struct wm8994 *wm8994)
|
|||
|
||||
void wm8994_irq_exit(struct wm8994 *wm8994)
|
||||
{
|
||||
if (wm8994->irq)
|
||||
free_irq(wm8994->irq, wm8994);
|
||||
regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
|
||||
}
|
||||
|
|
|
|||
1238
drivers/mfd/wm8994-regmap.c
Normal file
1238
drivers/mfd/wm8994-regmap.c
Normal file
File diff suppressed because it is too large
Load diff
25
drivers/mfd/wm8994.h
Normal file
25
drivers/mfd/wm8994.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* wm8994.h -- WM8994 MFD internals
|
||||
*
|
||||
* Copyright 2011 Wolfson Microelectronics PLC.
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_WM8994_H__
|
||||
#define __MFD_WM8994_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
extern struct regmap_config wm1811_regmap_config;
|
||||
extern struct regmap_config wm8994_regmap_config;
|
||||
extern struct regmap_config wm8958_regmap_config;
|
||||
extern struct regmap_config wm8994_base_regmap_config;
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue