summaryrefslogtreecommitdiff
path: root/drivers/mfd/arizona-core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-04 11:35:03 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-04 11:35:03 -0700
commit8bd8fd0a29bfd5ad8e1976edd8c4c40cdb39aa4f (patch)
tree1d7b2e30083194cc4223d9b150583fc2924bd032 /drivers/mfd/arizona-core.c
parent352712274507645b6f82b8763977ad87321919a3 (diff)
parent5a688c455066c21c133bc8ffa7b11f8c66b7fe0b (diff)
Merge tag 'mfd-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "New Device Support: - New Clocksource driver from ST - New MFD/ACPI/DMA drivers for Intel's Sunrisepoint PCH based platforms - Add support for Arizona WM8998 and WM1814 - Add support for Dialog Semi DA9062 and DA9063 - Add support for Kontron COMe-bBL6 and COMe-cBW6 - Add support for X-Powers AXP152 - Add support for Atmel, many - Add support for STMPE, many - Add support for USB in X-Powers AXP22X Core Frameworks: - New Base API to traverse devices and their children in reverse order Bug Fixes: - Fix race between runtime-suspend and IRQs - Obtain platform data form more reliable source Fix-ups: - Constifying things - Variable signage changes - Kconfig depends|selects changes - Make use of BIT() macro - Do not supply .owner attribute in *_driver structures - MAINTAINERS entries - Stop using set_irq_flags() - Start using irq_set_chained_handler_and_data() - Export DT device ID structures" * tag 'mfd-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits) mfd: jz4740-adc: Init mask cache in generic IRQ chip mfd: cros_ec: spi: Add OF match table mfd: stmpe: Add OF match table mfd: max77686: Split out regulator part from the DT binding mfd: Add DT binding for Maxim MAX77802 IC mfd: max77686: Use a generic name for the PMIC node in the example mfd: max77686: Don't suggest in binding to use a deprecated property mfd: Add MFD_CROS_EC dependencies mfd: cros_ec: Remove CROS_EC_PROTO dependency for SPI and I2C drivers mfd: axp20x: Add a cell for the usb power_supply part of the axp20x PMICs mfd: axp20x: Add missing registers, and mark more registers volatile mfd: arizona: Fixup some formatting/white space errors mfd: wm8994: Fix NULL pointer exception on missing pdata of: Add vendor prefix for Nuvoton mfd: mt6397: Implement wake handler and suspend/resume to handle wake up event mfd: atmel-hlcdc: Add support for new SoCs mfd: Export OF module alias information in missing drivers mfd: stw481x: Export I2C module alias information mfd: da9062: Support for the DA9063 OnKey in the DA9062 core mfd: max899x: Avoid redundant irq_data lookup ...
Diffstat (limited to 'drivers/mfd/arizona-core.c')
-rw-r--r--drivers/mfd/arizona-core.c138
1 files changed, 113 insertions, 25 deletions
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index a72ddb295078..08b36fa5b0c5 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -30,7 +30,7 @@
#include "arizona.h"
-static const char *wm5102_core_supplies[] = {
+static const char * const wm5102_core_supplies[] = {
"AVDD",
"DBVDD1",
};
@@ -146,17 +146,31 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
static irqreturn_t arizona_overclocked(int irq, void *data)
{
struct arizona *arizona = data;
- unsigned int val[2];
+ unsigned int val[3];
int ret;
-
+
ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
- &val[0], 2);
+ &val[0], 3);
if (ret != 0) {
dev_err(arizona->dev, "Failed to read overclock status: %d\n",
ret);
return IRQ_NONE;
}
+ switch (arizona->type) {
+ case WM8998:
+ case WM1814:
+ /* Some bits are shifted on WM8998,
+ * rearrange to match the standard bit layout
+ */
+ val[0] = ((val[0] & 0x60e0) >> 1) |
+ ((val[0] & 0x1e00) >> 2) |
+ (val[0] & 0x000f);
+ break;
+ default:
+ break;
+ }
+
if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
dev_err(arizona->dev, "PWM overclocked\n");
if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
@@ -201,6 +215,9 @@ static irqreturn_t arizona_overclocked(int irq, void *data)
if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
dev_err(arizona->dev, "ISRC1 overclocked\n");
+ if (val[2] & ARIZONA_SPDIF_OVERCLOCKED_STS)
+ dev_err(arizona->dev, "SPDIF overclocked\n");
+
return IRQ_HANDLED;
}
@@ -550,9 +567,8 @@ static int arizona_runtime_resume(struct device *dev)
break;
default:
ret = arizona_wait_for_boot(arizona);
- if (ret != 0) {
+ if (ret != 0)
goto err;
- }
if (arizona->external_dcvdd) {
ret = regmap_update_bits(arizona->regmap,
@@ -759,8 +775,8 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,gpio-defaults",
- arizona->pdata.gpio_defaults,
- ARRAY_SIZE(arizona->pdata.gpio_defaults));
+ pdata->gpio_defaults,
+ ARRAY_SIZE(pdata->gpio_defaults));
if (ret >= 0) {
/*
* All values are literal except out of range values
@@ -768,11 +784,11 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
* data which uses 0 as chip default and out of range
* as zero.
*/
- for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
- if (arizona->pdata.gpio_defaults[i] > 0xffff)
- arizona->pdata.gpio_defaults[i] = 0;
- else if (arizona->pdata.gpio_defaults[i] == 0)
- arizona->pdata.gpio_defaults[i] = 0x10000;
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+ if (pdata->gpio_defaults[i] > 0xffff)
+ pdata->gpio_defaults[i] = 0;
+ else if (pdata->gpio_defaults[i] == 0)
+ pdata->gpio_defaults[i] = 0x10000;
}
} else {
dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
@@ -781,20 +797,20 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop,
cur, val) {
- if (count == ARRAY_SIZE(arizona->pdata.inmode))
+ if (count == ARRAY_SIZE(pdata->inmode))
break;
- arizona->pdata.inmode[count] = val;
+ pdata->inmode[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop,
cur, val) {
- if (count == ARRAY_SIZE(arizona->pdata.dmic_ref))
+ if (count == ARRAY_SIZE(pdata->dmic_ref))
break;
- arizona->pdata.dmic_ref[count] = val;
+ pdata->dmic_ref[count] = val;
count++;
}
@@ -806,6 +822,8 @@ const struct of_device_id arizona_of_match[] = {
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
+ { .compatible = "wlf,wm8998", .data = (void *)WM8998 },
+ { .compatible = "wlf,wm1814", .data = (void *)WM1814 },
{},
};
EXPORT_SYMBOL_GPL(arizona_of_match);
@@ -820,7 +838,7 @@ static const struct mfd_cell early_devs[] = {
{ .name = "arizona-ldo1" },
};
-static const char *wm5102_supplies[] = {
+static const char * const wm5102_supplies[] = {
"MICVDD",
"DBVDD2",
"DBVDD3",
@@ -863,7 +881,7 @@ static const struct mfd_cell wm5110_devs[] = {
},
};
-static const char *wm8997_supplies[] = {
+static const char * const wm8997_supplies[] = {
"MICVDD",
"DBVDD2",
"CPVDD",
@@ -887,11 +905,28 @@ static const struct mfd_cell wm8997_devs[] = {
},
};
+static const struct mfd_cell wm8998_devs[] = {
+ {
+ .name = "arizona-extcon",
+ .parent_supplies = wm5102_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
+ { .name = "arizona-gpio" },
+ { .name = "arizona-haptics" },
+ { .name = "arizona-pwm" },
+ {
+ .name = "wm8998-codec",
+ .parent_supplies = wm5102_supplies,
+ .num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
+ },
+ { .name = "arizona-micsupp" },
+};
+
int arizona_dev_init(struct arizona *arizona)
{
struct device *dev = arizona->dev;
const char *type_name;
- unsigned int reg, val;
+ unsigned int reg, val, mask;
int (*apply_patch)(struct arizona *) = NULL;
int ret, i;
@@ -911,6 +946,8 @@ int arizona_dev_init(struct arizona *arizona)
case WM5110:
case WM8280:
case WM8997:
+ case WM8998:
+ case WM1814:
for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
arizona->core_supplies[i].supply
= wm5102_core_supplies[i];
@@ -992,6 +1029,7 @@ int arizona_dev_init(struct arizona *arizona)
switch (reg) {
case 0x5102:
case 0x5110:
+ case 0x6349:
case 0x8997:
break;
default:
@@ -1093,6 +1131,27 @@ int arizona_dev_init(struct arizona *arizona)
apply_patch = wm8997_patch;
break;
#endif
+#ifdef CONFIG_MFD_WM8998
+ case 0x6349:
+ switch (arizona->type) {
+ case WM8998:
+ type_name = "WM8998";
+ break;
+
+ case WM1814:
+ type_name = "WM1814";
+ break;
+
+ default:
+ type_name = "WM8998";
+ dev_err(arizona->dev, "WM8998 registered as %d\n",
+ arizona->type);
+ arizona->type = WM8998;
+ }
+
+ apply_patch = wm8998_patch;
+ break;
+#endif
default:
dev_err(arizona->dev, "Unknown device ID %x\n", reg);
goto err_reset;
@@ -1204,14 +1263,38 @@ int arizona_dev_init(struct arizona *arizona)
<< ARIZONA_IN1_DMIC_SUP_SHIFT;
if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC)
val |= 1 << ARIZONA_IN1_MODE_SHIFT;
- if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
- val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
+
+ switch (arizona->type) {
+ case WM8998:
+ case WM1814:
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
+ ARIZONA_IN1L_SRC_SE_MASK,
+ (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
+ << ARIZONA_IN1L_SRC_SE_SHIFT);
+
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
+ ARIZONA_IN1R_SRC_SE_MASK,
+ (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
+ << ARIZONA_IN1R_SRC_SE_SHIFT);
+
+ mask = ARIZONA_IN1_DMIC_SUP_MASK |
+ ARIZONA_IN1_MODE_MASK;
+ break;
+ default:
+ if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
+ val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
+
+ mask = ARIZONA_IN1_DMIC_SUP_MASK |
+ ARIZONA_IN1_MODE_MASK |
+ ARIZONA_IN1_SINGLE_ENDED_MASK;
+ break;
+ }
regmap_update_bits(arizona->regmap,
ARIZONA_IN1L_CONTROL + (i * 8),
- ARIZONA_IN1_DMIC_SUP_MASK |
- ARIZONA_IN1_MODE_MASK |
- ARIZONA_IN1_SINGLE_ENDED_MASK, val);
+ mask, val);
}
for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
@@ -1273,6 +1356,11 @@ int arizona_dev_init(struct arizona *arizona)
ret = mfd_add_devices(arizona->dev, -1, wm8997_devs,
ARRAY_SIZE(wm8997_devs), NULL, 0, NULL);
break;
+ case WM8998:
+ case WM1814:
+ ret = mfd_add_devices(arizona->dev, -1, wm8998_devs,
+ ARRAY_SIZE(wm8998_devs), NULL, 0, NULL);
+ break;
}
if (ret != 0) {