diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 08:35:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 08:35:35 -0700 |
commit | d042380886fb2fc6c4b0fcfe1214ba473769a8e9 (patch) | |
tree | 61e29ff167e0f83f67930ee9911062415030e1ef /drivers/mfd/arizona-core.c | |
parent | 3477d168ba61c5b0ca42d3d4642f3463609a5417 (diff) | |
parent | b8d336ed90f541097a2ce583be430bb3e895dfbd (diff) |
Merge tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core framework:
- Add the MFD bindings doc to MAINTAINERS
New drivers:
- X-Powers AC100 Audio CODEC and RTC
- TI LP873x PMIC
- Rockchip RK808 PMIC
- Samsung Exynos Low Power Audio
New device support:
- Add support for STMPE1600 variant to stmpe
- Add support for PM8018 PMIC to pm8921-core
- Add support for AXP806 PMIC in axp20x
- Add support for AXP209 GPIO in axp20x
New functionality:
- Add support for Reset to all STMPE variants
- Add support for MKBP event support to cros_ec
- Add support for USB to intel_soc_pmic_bxtwc
- Add support for IRQs and Power Button to tps65217
Fix-ups:
- Clean-up defunct author emails (da9063, max14577)
- Kconfig fixups (wm8350-i2c, as37220
- Constify (altera-a10sr, sm501)
- Supply PCI IDs (intel-lpss-pci)
- Improve clocking (qcom_rpm)
- Fix IRQ probing (ucb1x00-core)
- Ensure fault log is cleared (da9052)
- Remove NO_IRQ check (ucb1x00-core)
- Supply I2C properties (intel-lpss-acpi, intel-lpss-pci)
- Non standard declaration (tps65217, max8997-irq)
- Remove unused code (lp873x, db8500-prcmu, ab8500-debugfs,
cros_ec_spi)
- Make non-modular (altera-a10sr, intel_msic, smsc-ece1099,
sun6i-prcm, twl-core)
- OF bindings (ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x,
lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona)
Bugfixes:
- Release OF pointer (qcom_rpm)
- Avoid double shifting in suspend/resume (88pm80x)
- Fix 'defined but not used' error (exynos-lpass)
- Fix 'sleeping whilst attomic' (atmel-hlcdc)"
* tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits)
mfd: arizona: Handle probe deferral for reset GPIO
mfd: arizona: Remove arizona_of_get_named_gpio helper function
mfd: arizona: Add DT options for max_channels_clocked and PDM speaker config
mfd: twl6040: Register child device for twl6040-pdmclk
mfd: cros_ec_spi: Remove unused variable 'request'
mfd: omap-usb-host: Return value is not 'const int'
mfd: ab8500-debugfs: Remove 'weak' function suspend_test_wake_cause_interrupt_is_mine()
mfd: ab8500-debugfs: Remove ab8500_dump_all_banks_to_mem()
mfd: db8500-prcmu: Remove unused *prcmu_set_ddr_opp() calls
mfd: ab8500-debugfs: Prevent initialised field from being over-written
mfd: max8997-irq: 'inline' should be at the beginning of the declaration
mfd: rk808: Fix RK818_IRQ_DISCHG_ILIM initializer
mfd: tps65217: Fix nonstandard declaration
mfd: lp873x: Remove unused mutex lock from struct lp873x
mfd: atmel-hlcdc: Do not sleep in atomic context
mfd: exynos-lpass: Mark PM functions as __maybe_unused
mfd: intel-lpss: Add default I2C device properties for Apollo Lake
mfd: twl-core: Make it explicitly non-modular
mfd: sun6i-prcm: Make it explicitly non-modular
mfd: smsc-ece1099: Make it explicitly non-modular
...
Diffstat (limited to 'drivers/mfd/arizona-core.c')
-rw-r--r-- | drivers/mfd/arizona-core.c | 113 |
1 files changed, 81 insertions, 32 deletions
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index e4f97b3c824b..41767f7239bb 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> @@ -49,7 +50,15 @@ int arizona_clk32k_enable(struct arizona *arizona) case ARIZONA_32KZ_MCLK1: ret = pm_runtime_get_sync(arizona->dev); if (ret != 0) - goto out; + goto err_ref; + ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); + if (ret != 0) + goto err_pm; + break; + case ARIZONA_32KZ_MCLK2: + ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]); + if (ret != 0) + goto err_ref; break; } @@ -58,7 +67,9 @@ int arizona_clk32k_enable(struct arizona *arizona) ARIZONA_CLK_32K_ENA); } -out: +err_pm: + pm_runtime_put_sync(arizona->dev); +err_ref: if (ret != 0) arizona->clk32k_ref--; @@ -83,6 +94,10 @@ int arizona_clk32k_disable(struct arizona *arizona) switch (arizona->pdata.clk32k_src) { case ARIZONA_32KZ_MCLK1: pm_runtime_put_sync(arizona->dev); + clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]); + break; + case ARIZONA_32KZ_MCLK2: + clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]); break; } } @@ -735,7 +750,7 @@ static int arizona_suspend(struct device *dev) return 0; } -static int arizona_suspend_late(struct device *dev) +static int arizona_suspend_noirq(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); @@ -759,7 +774,7 @@ static int arizona_resume(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); - dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); + dev_dbg(arizona->dev, "Resume, reenabling IRQ\n"); enable_irq(arizona->irq); return 0; @@ -771,10 +786,8 @@ const struct dev_pm_ops arizona_pm_ops = { arizona_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) -#ifdef CONFIG_PM_SLEEP - .suspend_late = arizona_suspend_late, - .resume_noirq = arizona_resume_noirq, -#endif + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq, + arizona_resume_noirq) }; EXPORT_SYMBOL_GPL(arizona_pm_ops); @@ -790,35 +803,25 @@ unsigned long arizona_of_get_type(struct device *dev) } EXPORT_SYMBOL_GPL(arizona_of_get_type); -int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, - bool mandatory) -{ - int gpio; - - gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); - if (gpio < 0) { - if (mandatory) - dev_err(arizona->dev, - "Mandatory DT gpio %s missing/malformed: %d\n", - prop, gpio); - - gpio = 0; - } - - return gpio; -} -EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); - static int arizona_of_get_core_pdata(struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; struct property *prop; const __be32 *cur; u32 val; + u32 pdm_val[ARIZONA_MAX_PDM_SPK]; int ret, i; int count = 0; - pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); + pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0); + if (pdata->reset == -EPROBE_DEFER) { + return pdata->reset; + } else if (pdata->reset < 0) { + dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n", + pdata->reset); + + pdata->reset = 0; + } ret = of_property_read_u32_array(arizona->dev->of_node, "wlf,gpio-defaults", @@ -871,6 +874,35 @@ static int arizona_of_get_core_pdata(struct arizona *arizona) count++; } + count = 0; + of_property_for_each_u32(arizona->dev->of_node, + "wlf,max-channels-clocked", + prop, cur, val) { + if (count == ARRAY_SIZE(pdata->max_channels_clocked)) + break; + + pdata->max_channels_clocked[count] = val; + count++; + } + + ret = of_property_read_u32_array(arizona->dev->of_node, + "wlf,spk-fmt", + pdm_val, + ARRAY_SIZE(pdm_val)); + + if (ret >= 0) + for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count) + pdata->spk_fmt[count] = pdm_val[count]; + + ret = of_property_read_u32_array(arizona->dev->of_node, + "wlf,spk-mute", + pdm_val, + ARRAY_SIZE(pdm_val)); + + if (ret >= 0) + for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count) + pdata->spk_mute[count] = pdm_val[count]; + return 0; } @@ -1000,6 +1032,7 @@ static const struct mfd_cell wm8998_devs[] = { int arizona_dev_init(struct arizona *arizona) { + const char * const mclk_name[] = { "mclk1", "mclk2" }; struct device *dev = arizona->dev; const char *type_name = NULL; unsigned int reg, val, mask; @@ -1010,11 +1043,24 @@ int arizona_dev_init(struct arizona *arizona) dev_set_drvdata(arizona->dev, arizona); mutex_init(&arizona->clk_lock); - if (dev_get_platdata(arizona->dev)) + if (dev_get_platdata(arizona->dev)) { memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), sizeof(arizona->pdata)); - else - arizona_of_get_core_pdata(arizona); + } else { + ret = arizona_of_get_core_pdata(arizona); + if (ret < 0) + return ret; + } + + BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name)); + for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) { + arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]); + if (IS_ERR(arizona->mclk[i])) { + dev_info(arizona->dev, "Failed to get %s: %ld\n", + mclk_name[i], PTR_ERR(arizona->mclk[i])); + arizona->mclk[i] = NULL; + } + } regcache_cache_only(arizona->regmap, true); @@ -1035,7 +1081,7 @@ int arizona_dev_init(struct arizona *arizona) default: dev_err(arizona->dev, "Unknown device type %d\n", arizona->type); - return -EINVAL; + return -ENODEV; } /* Mark DCVDD as external, LDO1 driver will clear if internal */ @@ -1121,6 +1167,7 @@ int arizona_dev_init(struct arizona *arizona) break; default: dev_err(arizona->dev, "Unknown device ID: %x\n", reg); + ret = -ENODEV; goto err_reset; } @@ -1280,12 +1327,14 @@ int arizona_dev_init(struct arizona *arizona) break; default: dev_err(arizona->dev, "Unknown device ID %x\n", reg); + ret = -ENODEV; goto err_reset; } if (!subdevs) { dev_err(arizona->dev, "No kernel support for device ID %x\n", reg); + ret = -ENODEV; goto err_reset; } |