/* * Supplies for the main bulk of CODEC; the LDO supplies are ignored * and should be handled via the standard regulator API supply * management.
*/ staticconstchar *wm1811_main_supplies[] = { "DBVDD1", "DBVDD2", "DBVDD3", "DCVDD", "AVDD1", "AVDD2", "CPVDD", "SPKVDD1", "SPKVDD2",
};
/* Don't actually go through with the suspend if the CODEC is
* still active for accessory detect. */ switch (wm8994->type) { case WM8958: case WM1811:
ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1); if (ret < 0) {
dev_err(dev, "Failed to read power status: %d\n", ret);
} elseif (ret & WM8958_MICD_ENA) {
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)
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
/* 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,
wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
regcache_mark_dirty(wm8994->regmap);
/* Restore GPIO registers to prevent problems with mismatched * pin configurations.
*/
ret = regcache_sync_region(wm8994->regmap, WM8994_GPIO_1,
WM8994_GPIO_11); if (ret != 0)
dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
/* In case one of the GPIOs is used as a wake input. */
ret = regcache_sync_region(wm8994->regmap,
WM8994_INTERRUPT_STATUS_1_MASK,
WM8994_INTERRUPT_STATUS_1_MASK); if (ret != 0)
dev_err(dev, "Failed to restore interrupt mask: %d\n", ret);
ret = wm8994_set_pdata_from_of(wm8994); if (ret != 0) return ret;
/* Add the on-chip regulators first for bootstrapping */
ret = mfd_add_devices(wm8994->dev, 0,
wm8994_regulator_devs,
ARRAY_SIZE(wm8994_regulator_devs),
NULL, 0, NULL); if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret); goto err;
}
switch (wm8994->type) { case WM1811:
wm8994->num_supplies = ARRAY_SIZE(wm1811_main_supplies); break; case WM8994:
wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); break; case WM8958:
wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies); break; default:
BUG(); goto err;
}
wm8994->supplies = devm_kcalloc(wm8994->dev,
wm8994->num_supplies, sizeof(struct regulator_bulk_data),
GFP_KERNEL); if (!wm8994->supplies) {
ret = -ENOMEM; goto err;
}
switch (wm8994->type) { case WM1811: for (i = 0; i < ARRAY_SIZE(wm1811_main_supplies); i++)
wm8994->supplies[i].supply = wm1811_main_supplies[i]; break; case WM8994: for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
wm8994->supplies[i].supply = wm8994_main_supplies[i]; break; case WM8958: for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
wm8994->supplies[i].supply = wm8958_main_supplies[i]; break; default:
BUG(); goto err;
}
/* * Can't use devres helper here as some of the supplies are provided by * wm8994->dev's children (regulators) and those regulators are * unregistered by the devres core before the supplies are freed.
*/
ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
wm8994->supplies); if (ret != 0) { if (ret != -EPROBE_DEFER)
dev_err(wm8994->dev, "Failed to get supplies: %d\n",
ret); goto err;
}
ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) {
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); goto err_regulator_free;
}
ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); if (ret < 0) {
dev_err(wm8994->dev, "Failed to read ID register\n"); goto err_enable;
} switch (ret) { case 0x1811:
devname = "WM1811"; if (wm8994->type != WM1811)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM1811; break; case 0x8994:
devname = "WM8994"; if (wm8994->type != WM8994)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM8994; break; case 0x8958:
devname = "WM8958"; if (wm8994->type != WM8958)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM8958; break; default:
dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
ret);
ret = -EINVAL; goto err_enable;
}
ret = wm8994_reg_read(wm8994, WM8994_CHIP_REVISION); if (ret < 0) {
dev_err(wm8994->dev, "Failed to read revision register: %d\n",
ret); goto err_enable;
}
wm8994->revision = ret & WM8994_CHIP_REV_MASK;
wm8994->cust_id = (ret & WM8994_CUST_ID_MASK) >> WM8994_CUST_ID_SHIFT;
switch (wm8994->type) { case WM8994: switch (wm8994->revision) { case 0: case 1:
dev_warn(wm8994->dev, "revision %c not fully supported\n", 'A' + wm8994->revision); break; case 2: case 3: default:
regmap_patch = wm8994_revc_patch;
patch_regs = ARRAY_SIZE(wm8994_revc_patch); break;
} break;
case WM8958: switch (wm8994->revision) { case 0:
regmap_patch = wm8958_reva_patch;
patch_regs = ARRAY_SIZE(wm8958_reva_patch); break; default: break;
} break;
case WM1811: /* Revision C did not change the relevant layer */ if (wm8994->revision > 1)
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);
ret = -EINVAL; goto err_enable;
}
ret = regmap_reinit_cache(wm8994->regmap, regmap_config); if (ret != 0) {
dev_err(wm8994->dev, "Failed to reinit register cache: %d\n",
ret); goto err_enable;
}
/* Explicitly put the device into reset in case regulators * don't get disabled in order to ensure we know the device * state.
*/
ret = wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET)); if (ret != 0) {
dev_err(wm8994->dev, "Failed to reset device: %d\n", ret); goto err_enable;
}
if (regmap_patch) {
ret = regmap_register_patch(wm8994->regmap, regmap_patch,
patch_regs); if (ret != 0) {
dev_err(wm8994->dev, "Failed to register patch: %d\n",
ret); goto err_enable;
}
}
/* GPIO configuration is only applied if it's non-zero */ for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { if (pdata->gpio_defaults[i]) {
wm8994_set_bits(wm8994, WM8994_GPIO_1 + i,
0xffff, pdata->gpio_defaults[i]);
}
}
/* In some system designs where the regulators are not in use, * we can achieve a small reduction in leakage currents by * floating LDO outputs. This bit makes no difference if the * LDOs are enabled, it only affects cases where the LDOs were * in operation and are then disabled.
*/ for (i = 0; i < WM8994_NUM_LDO_REGS; i++) { if (wm8994_ldo_in_use(pdata, i))
wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
WM8994_LDO1_DISCH, WM8994_LDO1_DISCH); else
wm8994_set_bits(wm8994, WM8994_LDO_1 + i,
WM8994_LDO1_DISCH, 0);
}
wm8994_irq_init(wm8994);
ret = mfd_add_devices(wm8994->dev, -1,
wm8994_devs, ARRAY_SIZE(wm8994_devs),
NULL, 0, NULL); if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret); goto err_irq;
}
MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown ");
MODULE_SOFTDEP("pre: wm8994_regulator");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.