Lines Matching +full:cirrus +full:- +full:cs42l43 +full:- +full:state
1 // SPDX-License-Identifier: GPL-2.0
3 * CS42L43 core driver
5 * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
6 * Cirrus Logic International Semiconductor Ltd.
19 #include <linux/mfd/cs42l43.h>
20 #include <linux/mfd/cs42l43-regs.h>
28 #include "cs42l43.h"
440 #define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
496 .name = "cs42l43",
509 "vdd-a", "vdd-io", "vdd-cp",
512 static const char * const cs42l43_parent_supplies[] = { "vdd-amp" };
515 { .name = "cs42l43-pinctrl", },
516 { .name = "cs42l43-spi", },
518 .name = "cs42l43-codec",
529 static int cs42l43_soft_reset(struct cs42l43 *cs42l43) in cs42l43_soft_reset() argument
535 reinit_completion(&cs42l43->device_detach); in cs42l43_soft_reset()
541 regcache_cache_only(cs42l43->regmap, true); in cs42l43_soft_reset()
542 regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset)); in cs42l43_soft_reset()
546 if (cs42l43->sdw) { in cs42l43_soft_reset()
550 time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); in cs42l43_soft_reset()
552 dev_err(cs42l43->dev, "Timed out waiting for device detach\n"); in cs42l43_soft_reset()
553 return -ETIMEDOUT; in cs42l43_soft_reset()
557 return -EAGAIN; in cs42l43_soft_reset()
561 * This function is essentially a no-op on I2C, but will wait for the device to
564 static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43) in cs42l43_wait_for_attach() argument
566 if (!cs42l43->attached) { in cs42l43_wait_for_attach()
570 time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); in cs42l43_wait_for_attach()
572 dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n"); in cs42l43_wait_for_attach()
573 return -ETIMEDOUT; in cs42l43_wait_for_attach()
577 regcache_cache_only(cs42l43->regmap, false); in cs42l43_wait_for_attach()
580 if (cs42l43->sdw) in cs42l43_wait_for_attach()
581 regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL, in cs42l43_wait_for_attach()
596 static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow) in cs42l43_mcu_stage_2_3() argument
605 regmap_write(cs42l43->regmap, need_reg, 0); in cs42l43_mcu_stage_2_3()
607 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS, in cs42l43_mcu_stage_2_3()
611 dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); in cs42l43_mcu_stage_2_3()
615 return -EAGAIN; in cs42l43_mcu_stage_2_3()
631 static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43) in cs42l43_mcu_stage_3_2() argument
633 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS, in cs42l43_mcu_stage_3_2()
635 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0); in cs42l43_mcu_stage_3_2()
637 return cs42l43_soft_reset(cs42l43); in cs42l43_mcu_stage_3_2()
644 static int cs42l43_mcu_disable(struct cs42l43 *cs42l43) in cs42l43_mcu_disable() argument
649 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG, in cs42l43_mcu_disable()
651 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION, in cs42l43_mcu_disable()
653 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK); in cs42l43_mcu_disable()
654 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); in cs42l43_mcu_disable()
656 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, in cs42l43_mcu_disable()
660 dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val); in cs42l43_mcu_disable()
664 /* Soft reset to clear any register state the firmware left behind. */ in cs42l43_mcu_disable()
665 return cs42l43_soft_reset(cs42l43); in cs42l43_mcu_disable()
673 struct cs42l43 *cs42l43 = context; in cs42l43_mcu_load_firmware() local
679 dev_err(cs42l43->dev, "Failed to load firmware\n"); in cs42l43_mcu_load_firmware()
680 cs42l43->firmware_error = -ENODEV; in cs42l43_mcu_load_firmware()
684 hdr = (const struct cs42l43_patch_header *)&firmware->data[0]; in cs42l43_mcu_load_firmware()
685 loadaddr = le32_to_cpu(hdr->load_addr); in cs42l43_mcu_load_firmware()
687 if (le16_to_cpu(hdr->version) != CS42L43_MCU_UPDATE_FORMAT) { in cs42l43_mcu_load_firmware()
688 dev_err(cs42l43->dev, "Bad firmware file format: %d\n", hdr->version); in cs42l43_mcu_load_firmware()
689 cs42l43->firmware_error = -EINVAL; in cs42l43_mcu_load_firmware()
693 regmap_write(cs42l43->regmap, CS42L43_PATCH_START_ADDR, loadaddr); in cs42l43_mcu_load_firmware()
694 regmap_bulk_write(cs42l43->regmap, loadaddr + CS42L43_MCU_UPDATE_OFFSET, in cs42l43_mcu_load_firmware()
695 &firmware->data[0], firmware->size / sizeof(u32)); in cs42l43_mcu_load_firmware()
697 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_PATCH_IND_MASK); in cs42l43_mcu_load_firmware()
698 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); in cs42l43_mcu_load_firmware()
700 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, in cs42l43_mcu_load_firmware()
704 dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val); in cs42l43_mcu_load_firmware()
705 cs42l43->firmware_error = ret; in cs42l43_mcu_load_firmware()
712 complete(&cs42l43->firmware_download); in cs42l43_mcu_load_firmware()
715 static int cs42l43_mcu_is_hw_compatible(struct cs42l43 *cs42l43, in cs42l43_mcu_is_hw_compatible() argument
725 dev_err(cs42l43->dev, "Firmware too old to support disable\n"); in cs42l43_mcu_is_hw_compatible()
726 return -EINVAL; in cs42l43_mcu_is_hw_compatible()
735 * require the driver to wait for the device to re-attach on the SoundWire bus,
738 static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) in cs42l43_mcu_update_step() argument
745 regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev); in cs42l43_mcu_update_step()
747 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status); in cs42l43_mcu_update_step()
749 dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret); in cs42l43_mcu_update_step()
753 ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev); in cs42l43_mcu_update_step()
755 dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret); in cs42l43_mcu_update_step()
778 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); in cs42l43_mcu_update_step()
780 dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret); in cs42l43_mcu_update_step()
784 cs42l43->hw_lock = secure_cfg & CS42L43_LOCK_HW_STS_MASK; in cs42l43_mcu_update_step()
786 if (!patched && cs42l43->hw_lock) { in cs42l43_mcu_update_step()
787 dev_err(cs42l43->dev, "Unpatched secure device\n"); in cs42l43_mcu_update_step()
788 return -EPERM; in cs42l43_mcu_update_step()
791 dev_dbg(cs42l43->dev, "Firmware(0x%x, 0x%x) in boot stage %d\n", in cs42l43_mcu_update_step()
798 "cs42l43.bin", cs42l43->dev, in cs42l43_mcu_update_step()
799 GFP_KERNEL, cs42l43, in cs42l43_mcu_update_step()
802 dev_err(cs42l43->dev, "Failed to request firmware: %d\n", ret); in cs42l43_mcu_update_step()
806 wait_for_completion(&cs42l43->firmware_download); in cs42l43_mcu_update_step()
808 if (cs42l43->firmware_error) in cs42l43_mcu_update_step()
809 return cs42l43->firmware_error; in cs42l43_mcu_update_step()
811 return -EAGAIN; in cs42l43_mcu_update_step()
813 return cs42l43_mcu_stage_2_3(cs42l43, shadow); in cs42l43_mcu_update_step()
817 ret = cs42l43_mcu_is_hw_compatible(cs42l43, mcu_rev, bios_rev); in cs42l43_mcu_update_step()
821 return cs42l43_mcu_disable(cs42l43); in cs42l43_mcu_update_step()
823 return cs42l43_mcu_stage_3_2(cs42l43); in cs42l43_mcu_update_step()
828 dev_err(cs42l43->dev, "Invalid boot status: %d\n", boot_status); in cs42l43_mcu_update_step()
829 return -EINVAL; in cs42l43_mcu_update_step()
836 static int cs42l43_mcu_update(struct cs42l43 *cs42l43) in cs42l43_mcu_update() argument
841 ret = cs42l43_mcu_update_step(cs42l43); in cs42l43_mcu_update()
842 if (ret != -EAGAIN) in cs42l43_mcu_update()
845 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_mcu_update()
850 dev_err(cs42l43->dev, "Failed retrying update\n"); in cs42l43_mcu_update()
851 return -ETIMEDOUT; in cs42l43_mcu_update()
854 static int cs42l43_irq_config(struct cs42l43 *cs42l43) in cs42l43_irq_config() argument
860 if (cs42l43->sdw) in cs42l43_irq_config()
861 cs42l43->irq = cs42l43->sdw->irq; in cs42l43_irq_config()
863 cs42l43->irq_chip = cs42l43_irq_chip; in cs42l43_irq_config()
864 cs42l43->irq_chip.irq_drv_data = cs42l43; in cs42l43_irq_config()
866 irq_data = irq_get_irq_data(cs42l43->irq); in cs42l43_irq_config()
868 dev_err(cs42l43->dev, "Invalid IRQ: %d\n", cs42l43->irq); in cs42l43_irq_config()
869 return -EINVAL; in cs42l43_irq_config()
887 ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap, in cs42l43_irq_config()
888 cs42l43->irq, irq_flags, 0, in cs42l43_irq_config()
889 &cs42l43->irq_chip, &cs42l43->irq_data); in cs42l43_irq_config()
891 dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret); in cs42l43_irq_config()
895 dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n", in cs42l43_irq_config()
896 cs42l43->irq, irq_flags); in cs42l43_irq_config()
903 struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work); in cs42l43_boot_work() local
907 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_boot_work()
911 ret = regmap_read(cs42l43->regmap, CS42L43_DEVID, &devid); in cs42l43_boot_work()
913 dev_err(cs42l43->dev, "Failed to read devid: %d\n", ret); in cs42l43_boot_work()
921 dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid); in cs42l43_boot_work()
925 ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid); in cs42l43_boot_work()
927 dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret); in cs42l43_boot_work()
931 ret = regmap_read(cs42l43->regmap, CS42L43_OTP_REVISION_ID, &otp); in cs42l43_boot_work()
933 dev_err(cs42l43->dev, "Failed to read otp rev: %d\n", ret); in cs42l43_boot_work()
937 dev_info(cs42l43->dev, in cs42l43_boot_work()
940 ret = cs42l43_mcu_update(cs42l43); in cs42l43_boot_work()
944 ret = regmap_register_patch(cs42l43->regmap, cs42l43_reva_patch, in cs42l43_boot_work()
947 dev_err(cs42l43->dev, "Failed to apply register patch: %d\n", ret); in cs42l43_boot_work()
951 ret = cs42l43_irq_config(cs42l43); in cs42l43_boot_work()
955 ret = devm_mfd_add_devices(cs42l43->dev, PLATFORM_DEVID_NONE, in cs42l43_boot_work()
959 dev_err(cs42l43->dev, "Failed to add subdevices: %d\n", ret); in cs42l43_boot_work()
963 pm_runtime_mark_last_busy(cs42l43->dev); in cs42l43_boot_work()
964 pm_runtime_put_autosuspend(cs42l43->dev); in cs42l43_boot_work()
969 pm_runtime_put_sync(cs42l43->dev); in cs42l43_boot_work()
972 static int cs42l43_power_up(struct cs42l43 *cs42l43) in cs42l43_power_up() argument
976 ret = regulator_enable(cs42l43->vdd_p); in cs42l43_power_up()
978 dev_err(cs42l43->dev, "Failed to enable vdd-p: %d\n", ret); in cs42l43_power_up()
982 /* vdd-p must be on for 50uS before any other supply */ in cs42l43_power_up()
985 gpiod_set_value_cansleep(cs42l43->reset, 1); in cs42l43_power_up()
987 ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_up()
989 dev_err(cs42l43->dev, "Failed to enable core supplies: %d\n", ret); in cs42l43_power_up()
993 ret = regulator_enable(cs42l43->vdd_d); in cs42l43_power_up()
995 dev_err(cs42l43->dev, "Failed to enable vdd-d: %d\n", ret); in cs42l43_power_up()
1004 regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_up()
1006 gpiod_set_value_cansleep(cs42l43->reset, 0); in cs42l43_power_up()
1007 regulator_disable(cs42l43->vdd_p); in cs42l43_power_up()
1012 static int cs42l43_power_down(struct cs42l43 *cs42l43) in cs42l43_power_down() argument
1016 ret = regulator_disable(cs42l43->vdd_d); in cs42l43_power_down()
1018 dev_err(cs42l43->dev, "Failed to disable vdd-d: %d\n", ret); in cs42l43_power_down()
1022 ret = regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_down()
1024 dev_err(cs42l43->dev, "Failed to disable core supplies: %d\n", ret); in cs42l43_power_down()
1028 gpiod_set_value_cansleep(cs42l43->reset, 0); in cs42l43_power_down()
1030 ret = regulator_disable(cs42l43->vdd_p); in cs42l43_power_down()
1032 dev_err(cs42l43->dev, "Failed to disable vdd-p: %d\n", ret); in cs42l43_power_down()
1039 int cs42l43_dev_probe(struct cs42l43 *cs42l43) in cs42l43_dev_probe() argument
1043 dev_set_drvdata(cs42l43->dev, cs42l43); in cs42l43_dev_probe()
1045 mutex_init(&cs42l43->pll_lock); in cs42l43_dev_probe()
1046 init_completion(&cs42l43->device_attach); in cs42l43_dev_probe()
1047 init_completion(&cs42l43->device_detach); in cs42l43_dev_probe()
1048 init_completion(&cs42l43->firmware_download); in cs42l43_dev_probe()
1049 INIT_WORK(&cs42l43->boot_work, cs42l43_boot_work); in cs42l43_dev_probe()
1051 regcache_cache_only(cs42l43->regmap, true); in cs42l43_dev_probe()
1053 cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW); in cs42l43_dev_probe()
1054 if (IS_ERR(cs42l43->reset)) in cs42l43_dev_probe()
1055 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), in cs42l43_dev_probe()
1058 cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); in cs42l43_dev_probe()
1059 if (IS_ERR(cs42l43->vdd_p)) in cs42l43_dev_probe()
1060 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), in cs42l43_dev_probe()
1061 "Failed to get vdd-p\n"); in cs42l43_dev_probe()
1063 cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d"); in cs42l43_dev_probe()
1064 if (IS_ERR(cs42l43->vdd_d)) in cs42l43_dev_probe()
1065 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d), in cs42l43_dev_probe()
1066 "Failed to get vdd-d\n"); in cs42l43_dev_probe()
1071 cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i]; in cs42l43_dev_probe()
1073 ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES, in cs42l43_dev_probe()
1074 cs42l43->core_supplies); in cs42l43_dev_probe()
1076 return dev_err_probe(cs42l43->dev, ret, in cs42l43_dev_probe()
1079 ret = cs42l43_power_up(cs42l43); in cs42l43_dev_probe()
1083 pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS); in cs42l43_dev_probe()
1084 pm_runtime_use_autosuspend(cs42l43->dev); in cs42l43_dev_probe()
1085 pm_runtime_set_active(cs42l43->dev); in cs42l43_dev_probe()
1090 pm_runtime_get_noresume(cs42l43->dev); in cs42l43_dev_probe()
1091 ret = devm_pm_runtime_enable(cs42l43->dev); in cs42l43_dev_probe()
1095 queue_work(system_long_wq, &cs42l43->boot_work); in cs42l43_dev_probe()
1101 void cs42l43_dev_remove(struct cs42l43 *cs42l43) in cs42l43_dev_remove() argument
1103 cancel_work_sync(&cs42l43->boot_work); in cs42l43_dev_remove()
1105 cs42l43_power_down(cs42l43); in cs42l43_dev_remove()
1111 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_suspend() local
1134 dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret); in cs42l43_suspend()
1138 /* The IRQs will be re-enabled on resume by the cache sync */ in cs42l43_suspend()
1139 ret = regmap_multi_reg_write_bypassed(cs42l43->regmap, in cs42l43_suspend()
1142 dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret); in cs42l43_suspend()
1148 dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret); in cs42l43_suspend()
1155 ret = cs42l43_power_down(cs42l43); in cs42l43_suspend()
1159 disable_irq(cs42l43->irq); in cs42l43_suspend()
1166 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_suspend_noirq() local
1168 enable_irq(cs42l43->irq); in cs42l43_suspend_noirq()
1175 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_resume_noirq() local
1177 disable_irq(cs42l43->irq); in cs42l43_resume_noirq()
1184 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_resume() local
1187 ret = cs42l43_power_up(cs42l43); in cs42l43_resume()
1191 enable_irq(cs42l43->irq); in cs42l43_resume()
1195 dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); in cs42l43_resume()
1204 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_runtime_suspend() local
1211 regcache_cache_only(cs42l43->regmap, true); in cs42l43_runtime_suspend()
1218 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_runtime_resume() local
1222 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_runtime_resume()
1226 ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary); in cs42l43_runtime_resume()
1228 dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret); in cs42l43_runtime_resume()
1234 * If the canary has cleared the chip has reset, re-handle the in cs42l43_runtime_resume()
1237 ret = cs42l43_mcu_update(cs42l43); in cs42l43_runtime_resume()
1241 regcache_mark_dirty(cs42l43->regmap); in cs42l43_runtime_resume()
1244 ret = regcache_sync(cs42l43->regmap); in cs42l43_runtime_resume()
1246 dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret); in cs42l43_runtime_resume()
1253 regcache_cache_only(cs42l43->regmap, true); in cs42l43_runtime_resume()
1264 MODULE_DESCRIPTION("CS42L43 Core Driver");
1265 MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
1267 MODULE_FIRMWARE("cs42l43.bin");