ASoC: cs42l51: add power management
authorOlivier Moysan <olivier.moysan@st.com>
Wed, 3 Apr 2019 13:23:36 +0000 (15:23 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 4 Apr 2019 13:56:08 +0000 (20:56 +0700)
Add sleep PM callbacks to support system low power modes.

Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/cs42l51-i2c.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l51.h

index 8333dbf18ea29ebe18baf39a653ae2a748a58f69..116221e581ce5a3e9532198c1f98cb9f92c296c4 100644 (file)
@@ -29,8 +29,6 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
        struct regmap_config config;
 
        config = cs42l51_regmap;
-       config.val_bits = 8;
-       config.reg_bits = 8;
 
        return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
 }
@@ -40,10 +38,15 @@ static int cs42l51_i2c_remove(struct i2c_client *i2c)
        return cs42l51_remove(&i2c->dev);
 }
 
+static const struct dev_pm_ops cs42l51_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
+};
+
 static struct i2c_driver cs42l51_i2c_driver = {
        .driver = {
                .name = "cs42l51",
                .of_match_table = cs42l51_of_match,
+               .pm = &cs42l51_pm_ops,
        },
        .probe = cs42l51_i2c_probe,
        .remove = cs42l51_i2c_remove,
index 397b68901d1ce104856c591330b5c004dfee9810..b8f43858876a78399eb6449b4eb81a8408fcd919 100644 (file)
@@ -56,6 +56,7 @@ struct cs42l51_private {
        enum master_slave_mode func;
        struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
        struct gpio_desc *reset_gpio;
+       struct regmap *regmap;
 };
 
 #define CS42L51_FORMATS ( \
@@ -575,7 +576,106 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
        .non_legacy_dai_naming  = 1,
 };
 
+static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L51_POWER_CTL1:
+       case CS42L51_MIC_POWER_CTL:
+       case CS42L51_INTF_CTL:
+       case CS42L51_MIC_CTL:
+       case CS42L51_ADC_CTL:
+       case CS42L51_ADC_INPUT:
+       case CS42L51_DAC_OUT_CTL:
+       case CS42L51_DAC_CTL:
+       case CS42L51_ALC_PGA_CTL:
+       case CS42L51_ALC_PGB_CTL:
+       case CS42L51_ADCA_ATT:
+       case CS42L51_ADCB_ATT:
+       case CS42L51_ADCA_VOL:
+       case CS42L51_ADCB_VOL:
+       case CS42L51_PCMA_VOL:
+       case CS42L51_PCMB_VOL:
+       case CS42L51_BEEP_FREQ:
+       case CS42L51_BEEP_VOL:
+       case CS42L51_BEEP_CONF:
+       case CS42L51_TONE_CTL:
+       case CS42L51_AOUTA_VOL:
+       case CS42L51_AOUTB_VOL:
+       case CS42L51_PCM_MIXER:
+       case CS42L51_LIMIT_THRES_DIS:
+       case CS42L51_LIMIT_REL:
+       case CS42L51_LIMIT_ATT:
+       case CS42L51_ALC_EN:
+       case CS42L51_ALC_REL:
+       case CS42L51_ALC_THRES:
+       case CS42L51_NOISE_CONF:
+       case CS42L51_CHARGE_FREQ:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42l51_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L51_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42l51_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L51_CHIP_REV_ID:
+       case CS42L51_POWER_CTL1:
+       case CS42L51_MIC_POWER_CTL:
+       case CS42L51_INTF_CTL:
+       case CS42L51_MIC_CTL:
+       case CS42L51_ADC_CTL:
+       case CS42L51_ADC_INPUT:
+       case CS42L51_DAC_OUT_CTL:
+       case CS42L51_DAC_CTL:
+       case CS42L51_ALC_PGA_CTL:
+       case CS42L51_ALC_PGB_CTL:
+       case CS42L51_ADCA_ATT:
+       case CS42L51_ADCB_ATT:
+       case CS42L51_ADCA_VOL:
+       case CS42L51_ADCB_VOL:
+       case CS42L51_PCMA_VOL:
+       case CS42L51_PCMB_VOL:
+       case CS42L51_BEEP_FREQ:
+       case CS42L51_BEEP_VOL:
+       case CS42L51_BEEP_CONF:
+       case CS42L51_TONE_CTL:
+       case CS42L51_AOUTA_VOL:
+       case CS42L51_AOUTB_VOL:
+       case CS42L51_PCM_MIXER:
+       case CS42L51_LIMIT_THRES_DIS:
+       case CS42L51_LIMIT_REL:
+       case CS42L51_LIMIT_ATT:
+       case CS42L51_ALC_EN:
+       case CS42L51_ALC_REL:
+       case CS42L51_ALC_THRES:
+       case CS42L51_NOISE_CONF:
+       case CS42L51_STATUS:
+       case CS42L51_CHARGE_FREQ:
+               return true;
+       default:
+               return false;
+       }
+}
+
 const struct regmap_config cs42l51_regmap = {
+       .reg_bits = 8,
+       .reg_stride = 1,
+       .val_bits = 8,
+       .use_single_write = true,
+       .readable_reg = cs42l51_readable_reg,
+       .volatile_reg = cs42l51_volatile_reg,
+       .writeable_reg = cs42l51_writeable_reg,
        .max_register = CS42L51_CHARGE_FREQ,
        .cache_type = REGCACHE_RBTREE,
 };
@@ -596,6 +696,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
                return -ENOMEM;
 
        dev_set_drvdata(dev, cs42l51);
+       cs42l51->regmap = regmap;
 
        cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
        if (IS_ERR(cs42l51->mclk_handle)) {
@@ -673,6 +774,27 @@ int cs42l51_remove(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(cs42l51_remove);
 
+int __maybe_unused cs42l51_suspend(struct device *dev)
+{
+       struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs42l51->regmap, true);
+       regcache_mark_dirty(cs42l51->regmap);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cs42l51_suspend);
+
+int __maybe_unused cs42l51_resume(struct device *dev)
+{
+       struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
+
+       regcache_cache_only(cs42l51->regmap, false);
+
+       return regcache_sync(cs42l51->regmap);
+}
+EXPORT_SYMBOL_GPL(cs42l51_resume);
+
 const struct of_device_id cs42l51_of_match[] = {
        { .compatible = "cirrus,cs42l51", },
        { }
index aef0ede82c7b35697449601d1a3e64172d40148e..79dee01137c88779f84bc8ca69fcd23a43c936f5 100644 (file)
@@ -23,6 +23,8 @@ struct device;
 extern const struct regmap_config cs42l51_regmap;
 int cs42l51_probe(struct device *dev, struct regmap *regmap);
 int cs42l51_remove(struct device *dev);
+int __maybe_unused cs42l51_suspend(struct device *dev);
+int __maybe_unused cs42l51_resume(struct device *dev);
 extern const struct of_device_id cs42l51_of_match[];
 
 #define CS42L51_CHIP_ID                        0x1B