cs35l45.c (74b14e2850a34740c121cf2758d4181063d4c77c) cs35l45.c (6c07be8fe92c6b0c24ee1c599601dce3506b83c7)
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2//
3// cs35l45.c - CS35L45 ALSA SoC audio driver
4//
5// Copyright 2019-2022 Cirrus Logic, Inc.
6//
7// Author: James Schulman <james.schulman@cirrus.com>
8

--- 22 unchanged lines hidden (view full) ---

31 case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:
32 return (sts == CSPL_MBOX_STS_PAUSED);
33 case CSPL_MBOX_CMD_RESUME:
34 return (sts == CSPL_MBOX_STS_RUNNING);
35 case CSPL_MBOX_CMD_REINIT:
36 return (sts == CSPL_MBOX_STS_RUNNING);
37 case CSPL_MBOX_CMD_STOP_PRE_REINIT:
38 return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2//
3// cs35l45.c - CS35L45 ALSA SoC audio driver
4//
5// Copyright 2019-2022 Cirrus Logic, Inc.
6//
7// Author: James Schulman <james.schulman@cirrus.com>
8

--- 22 unchanged lines hidden (view full) ---

31 case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:
32 return (sts == CSPL_MBOX_STS_PAUSED);
33 case CSPL_MBOX_CMD_RESUME:
34 return (sts == CSPL_MBOX_STS_RUNNING);
35 case CSPL_MBOX_CMD_REINIT:
36 return (sts == CSPL_MBOX_STS_RUNNING);
37 case CSPL_MBOX_CMD_STOP_PRE_REINIT:
38 return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
39 case CSPL_MBOX_CMD_HIBERNATE:
40 return (sts == CSPL_MBOX_STS_HIBERNATE);
39 default:
40 return false;
41 }
42}
43
44static int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private *cs35l45,
45 struct regmap *regmap,
46 const enum cs35l45_cspl_mboxcmd cmd)

--- 692 unchanged lines hidden (view full) ---

739 .controls = cs35l45_controls,
740 .num_controls = ARRAY_SIZE(cs35l45_controls),
741
742 .name = "cs35l45",
743
744 .endianness = 1,
745};
746
41 default:
42 return false;
43 }
44}
45
46static int cs35l45_set_cspl_mbox_cmd(struct cs35l45_private *cs35l45,
47 struct regmap *regmap,
48 const enum cs35l45_cspl_mboxcmd cmd)

--- 692 unchanged lines hidden (view full) ---

741 .controls = cs35l45_controls,
742 .num_controls = ARRAY_SIZE(cs35l45_controls),
743
744 .name = "cs35l45",
745
746 .endianness = 1,
747};
748
749static void cs35l45_setup_hibernate(struct cs35l45_private *cs35l45)
750{
751 unsigned int wksrc;
752
753 if (cs35l45->bus_type == CONTROL_BUS_I2C)
754 wksrc = CS35L45_WKSRC_I2C;
755 else
756 wksrc = CS35L45_WKSRC_SPI;
757
758 regmap_update_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,
759 CS35L45_WKSRC_EN_MASK,
760 wksrc << CS35L45_WKSRC_EN_SHIFT);
761
762 regmap_set_bits(cs35l45->regmap, CS35L45_WAKESRC_CTL,
763 CS35L45_UPDT_WKCTL_MASK);
764
765 regmap_update_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,
766 CS35L45_WKI2C_ADDR_MASK, cs35l45->i2c_addr);
767
768 regmap_set_bits(cs35l45->regmap, CS35L45_WKI2C_CTL,
769 CS35L45_UPDT_WKI2C_MASK);
770}
771
772static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45)
773{
774 dev_dbg(cs35l45->dev, "Enter hibernate\n");
775
776 cs35l45_setup_hibernate(cs35l45);
777
778 // Don't wait for ACK since bus activity would wake the device
779 regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
780
781 return 0;
782}
783
784static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
785{
786 const int wake_retries = 20;
787 const int sleep_retries = 5;
788 int ret, i, j;
789
790 for (i = 0; i < sleep_retries; i++) {
791 dev_dbg(cs35l45->dev, "Exit hibernate\n");
792
793 for (j = 0; j < wake_retries; j++) {
794 ret = cs35l45_set_cspl_mbox_cmd(cs35l45, cs35l45->regmap,
795 CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
796 if (!ret) {
797 dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j);
798 return 0;
799 }
800 usleep_range(100, 200);
801 }
802
803 dev_err(cs35l45->dev, "Wake failed, re-enter hibernate: %d\n", ret);
804
805 cs35l45_setup_hibernate(cs35l45);
806 }
807
808 dev_err(cs35l45->dev, "Timed out waking device\n");
809
810 return -ETIMEDOUT;
811}
812
747static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
748{
749 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
750
813static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
814{
815 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
816
817 if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)
818 return 0;
819
820 cs35l45_enter_hibernate(cs35l45);
821
751 regcache_cache_only(cs35l45->regmap, true);
822 regcache_cache_only(cs35l45->regmap, true);
823 regcache_mark_dirty(cs35l45->regmap);
752
753 dev_dbg(cs35l45->dev, "Runtime suspended\n");
754
755 return 0;
756}
757
758static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
759{
760 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
761 int ret;
762
824
825 dev_dbg(cs35l45->dev, "Runtime suspended\n");
826
827 return 0;
828}
829
830static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
831{
832 struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
833 int ret;
834
835 if (!cs35l45->dsp.preloaded || !cs35l45->dsp.cs_dsp.running)
836 return 0;
837
763 dev_dbg(cs35l45->dev, "Runtime resume\n");
764
765 regcache_cache_only(cs35l45->regmap, false);
838 dev_dbg(cs35l45->dev, "Runtime resume\n");
839
840 regcache_cache_only(cs35l45->regmap, false);
841
842 ret = cs35l45_exit_hibernate(cs35l45);
843 if (ret)
844 return ret;
845
766 ret = regcache_sync(cs35l45->regmap);
767 if (ret != 0)
768 dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);
769
770 /* Clear global error status */
771 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
772 regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
773 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);

--- 446 unchanged lines hidden ---
846 ret = regcache_sync(cs35l45->regmap);
847 if (ret != 0)
848 dev_warn(cs35l45->dev, "regcache_sync failed: %d\n", ret);
849
850 /* Clear global error status */
851 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
852 regmap_set_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);
853 regmap_clear_bits(cs35l45->regmap, CS35L45_ERROR_RELEASE, CS35L45_GLOBAL_ERR_RLS_MASK);

--- 446 unchanged lines hidden ---