Lines Matching +full:firmware +full:- +full:reset
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
14 #include <linux/firmware.h>
17 #include <linux/mfd/cs42l43-regs.h>
431 #define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
500 "vdd-a", "vdd-io", "vdd-cp",
503 static const char * const cs42l43_parent_supplies[] = { "vdd-amp" };
506 { .name = "cs42l43-pinctrl", },
507 { .name = "cs42l43-spi", },
509 .name = "cs42l43-codec",
522 static const struct reg_sequence reset[] = { in cs42l43_soft_reset() local
526 reinit_completion(&cs42l43->device_detach); in cs42l43_soft_reset()
529 * Apply cache only because the soft reset will cause the device to in cs42l43_soft_reset()
532 regcache_cache_only(cs42l43->regmap, true); in cs42l43_soft_reset()
533 regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset)); in cs42l43_soft_reset()
537 if (cs42l43->sdw) { in cs42l43_soft_reset()
541 time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); in cs42l43_soft_reset()
543 dev_err(cs42l43->dev, "Timed out waiting for device detach\n"); in cs42l43_soft_reset()
544 return -ETIMEDOUT; in cs42l43_soft_reset()
548 return -EAGAIN; in cs42l43_soft_reset()
552 * This function is essentially a no-op on I2C, but will wait for the device to
557 if (!cs42l43->attached) { in cs42l43_wait_for_attach()
561 time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); in cs42l43_wait_for_attach()
563 dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n"); in cs42l43_wait_for_attach()
564 return -ETIMEDOUT; in cs42l43_wait_for_attach()
568 regcache_cache_only(cs42l43->regmap, false); in cs42l43_wait_for_attach()
571 if (cs42l43->sdw) in cs42l43_wait_for_attach()
572 regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL, in cs42l43_wait_for_attach()
579 * This function will advance the firmware into boot stage 3 from boot stage 2.
580 * Boot stage 3 is required to send commands to the firmware. This is achieved
581 * by setting the firmware NEED configuration register to zero, this indicates
582 * no configuration is required forcing the firmware to advance to boot stage 3.
584 * Later revisions of the firmware require the use of an alternative register
596 regmap_write(cs42l43->regmap, need_reg, 0); in cs42l43_mcu_stage_2_3()
598 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS, in cs42l43_mcu_stage_2_3()
602 dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); in cs42l43_mcu_stage_2_3()
606 return -EAGAIN; in cs42l43_mcu_stage_2_3()
610 * This function will return the firmware to boot stage 2 from boot stage 3.
611 * Boot stage 2 is required to apply updates to the firmware. This is achieved
612 * by setting the firmware NEED configuration register to FW_PATCH_NEED_CFG,
614 * firmware will see it is missing a patch configuration and will pause in boot
618 * register here as the driver will only return to boot stage 2 if the firmware
624 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS, in cs42l43_mcu_stage_3_2()
626 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0); in cs42l43_mcu_stage_3_2()
632 * Disable the firmware running on the device such that the driver can access
640 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG, in cs42l43_mcu_disable()
642 regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION, in cs42l43_mcu_disable()
644 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK); in cs42l43_mcu_disable()
645 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); in cs42l43_mcu_disable()
647 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, in cs42l43_mcu_disable()
651 dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val); in cs42l43_mcu_disable()
655 /* Soft reset to clear any register state the firmware left behind. */ in cs42l43_mcu_disable()
660 * Callback to load firmware updates.
662 static void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *context) in cs42l43_mcu_load_firmware() argument
669 if (!firmware) { in cs42l43_mcu_load_firmware()
670 dev_err(cs42l43->dev, "Failed to load firmware\n"); in cs42l43_mcu_load_firmware()
671 cs42l43->firmware_error = -ENODEV; in cs42l43_mcu_load_firmware()
675 hdr = (const struct cs42l43_patch_header *)&firmware->data[0]; in cs42l43_mcu_load_firmware()
676 loadaddr = le32_to_cpu(hdr->load_addr); in cs42l43_mcu_load_firmware()
678 if (le16_to_cpu(hdr->version) != CS42L43_MCU_UPDATE_FORMAT) { in cs42l43_mcu_load_firmware()
679 dev_err(cs42l43->dev, "Bad firmware file format: %d\n", hdr->version); in cs42l43_mcu_load_firmware()
680 cs42l43->firmware_error = -EINVAL; in cs42l43_mcu_load_firmware()
684 regmap_write(cs42l43->regmap, CS42L43_PATCH_START_ADDR, loadaddr); in cs42l43_mcu_load_firmware()
685 regmap_bulk_write(cs42l43->regmap, loadaddr + CS42L43_MCU_UPDATE_OFFSET, in cs42l43_mcu_load_firmware()
686 &firmware->data[0], firmware->size / sizeof(u32)); in cs42l43_mcu_load_firmware()
688 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_PATCH_IND_MASK); in cs42l43_mcu_load_firmware()
689 regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); in cs42l43_mcu_load_firmware()
691 ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, in cs42l43_mcu_load_firmware()
695 dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val); in cs42l43_mcu_load_firmware()
696 cs42l43->firmware_error = ret; in cs42l43_mcu_load_firmware()
701 release_firmware(firmware); in cs42l43_mcu_load_firmware()
703 complete(&cs42l43->firmware_download); in cs42l43_mcu_load_firmware()
707 * The process of updating the firmware is split into a series of steps, at the
708 * end of each step a soft reset of the device might be required which will
709 * require the driver to wait for the device to re-attach on the SoundWire bus,
719 regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev); in cs42l43_mcu_update_step()
721 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status); in cs42l43_mcu_update_step()
723 dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret); in cs42l43_mcu_update_step()
727 ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev); in cs42l43_mcu_update_step()
729 dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret); in cs42l43_mcu_update_step()
742 * The firmware has two revision numbers bringing either of them up to a in cs42l43_mcu_update_step()
753 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); in cs42l43_mcu_update_step()
755 dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret); in cs42l43_mcu_update_step()
759 cs42l43->hw_lock = secure_cfg & CS42L43_LOCK_HW_STS_MASK; in cs42l43_mcu_update_step()
761 if (!patched && cs42l43->hw_lock) { in cs42l43_mcu_update_step()
762 dev_err(cs42l43->dev, "Unpatched secure device\n"); in cs42l43_mcu_update_step()
763 return -EPERM; in cs42l43_mcu_update_step()
766 dev_dbg(cs42l43->dev, "Firmware(0x%x, 0x%x) in boot stage %d\n", in cs42l43_mcu_update_step()
773 "cs42l43.bin", cs42l43->dev, in cs42l43_mcu_update_step()
777 dev_err(cs42l43->dev, "Failed to request firmware: %d\n", ret); in cs42l43_mcu_update_step()
781 wait_for_completion(&cs42l43->firmware_download); in cs42l43_mcu_update_step()
783 if (cs42l43->firmware_error) in cs42l43_mcu_update_step()
784 return cs42l43->firmware_error; in cs42l43_mcu_update_step()
786 return -EAGAIN; in cs42l43_mcu_update_step()
798 dev_err(cs42l43->dev, "Invalid boot status: %d\n", boot_status); in cs42l43_mcu_update_step()
799 return -EINVAL; in cs42l43_mcu_update_step()
804 * Update the firmware running on the device.
812 if (ret != -EAGAIN) in cs42l43_mcu_update()
820 dev_err(cs42l43->dev, "Failed retrying update\n"); in cs42l43_mcu_update()
821 return -ETIMEDOUT; in cs42l43_mcu_update()
830 if (cs42l43->sdw) in cs42l43_irq_config()
831 cs42l43->irq = cs42l43->sdw->irq; in cs42l43_irq_config()
833 cs42l43->irq_chip = cs42l43_irq_chip; in cs42l43_irq_config()
834 cs42l43->irq_chip.irq_drv_data = cs42l43; in cs42l43_irq_config()
836 irq_data = irq_get_irq_data(cs42l43->irq); in cs42l43_irq_config()
838 dev_err(cs42l43->dev, "Invalid IRQ: %d\n", cs42l43->irq); in cs42l43_irq_config()
839 return -EINVAL; in cs42l43_irq_config()
857 ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap, in cs42l43_irq_config()
858 cs42l43->irq, irq_flags, 0, in cs42l43_irq_config()
859 &cs42l43->irq_chip, &cs42l43->irq_data); in cs42l43_irq_config()
861 dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret); in cs42l43_irq_config()
865 dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n", in cs42l43_irq_config()
866 cs42l43->irq, irq_flags); in cs42l43_irq_config()
881 ret = regmap_read(cs42l43->regmap, CS42L43_DEVID, &devid); in cs42l43_boot_work()
883 dev_err(cs42l43->dev, "Failed to read devid: %d\n", ret); in cs42l43_boot_work()
891 dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid); in cs42l43_boot_work()
895 ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid); in cs42l43_boot_work()
897 dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret); in cs42l43_boot_work()
901 ret = regmap_read(cs42l43->regmap, CS42L43_OTP_REVISION_ID, &otp); in cs42l43_boot_work()
903 dev_err(cs42l43->dev, "Failed to read otp rev: %d\n", ret); in cs42l43_boot_work()
907 dev_info(cs42l43->dev, in cs42l43_boot_work()
914 ret = regmap_register_patch(cs42l43->regmap, cs42l43_reva_patch, in cs42l43_boot_work()
917 dev_err(cs42l43->dev, "Failed to apply register patch: %d\n", ret); in cs42l43_boot_work()
925 ret = devm_mfd_add_devices(cs42l43->dev, PLATFORM_DEVID_NONE, in cs42l43_boot_work()
929 dev_err(cs42l43->dev, "Failed to add subdevices: %d\n", ret); in cs42l43_boot_work()
933 pm_runtime_mark_last_busy(cs42l43->dev); in cs42l43_boot_work()
934 pm_runtime_put_autosuspend(cs42l43->dev); in cs42l43_boot_work()
939 pm_runtime_put_sync(cs42l43->dev); in cs42l43_boot_work()
947 ret = regulator_enable(cs42l43->vdd_p); in cs42l43_power_up()
949 dev_err(cs42l43->dev, "Failed to enable vdd-p: %d\n", ret); in cs42l43_power_up()
953 /* vdd-p must be on for 50uS before any other supply */ in cs42l43_power_up()
956 gpiod_set_value_cansleep(cs42l43->reset, 1); in cs42l43_power_up()
958 ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_up()
960 dev_err(cs42l43->dev, "Failed to enable core supplies: %d\n", ret); in cs42l43_power_up()
964 ret = regulator_enable(cs42l43->vdd_d); in cs42l43_power_up()
966 dev_err(cs42l43->dev, "Failed to enable vdd-d: %d\n", ret); in cs42l43_power_up()
975 regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_up()
977 gpiod_set_value_cansleep(cs42l43->reset, 0); in cs42l43_power_up()
978 regulator_disable(cs42l43->vdd_p); in cs42l43_power_up()
987 ret = regulator_disable(cs42l43->vdd_d); in cs42l43_power_down()
989 dev_err(cs42l43->dev, "Failed to disable vdd-d: %d\n", ret); in cs42l43_power_down()
993 ret = regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); in cs42l43_power_down()
995 dev_err(cs42l43->dev, "Failed to disable core supplies: %d\n", ret); in cs42l43_power_down()
999 gpiod_set_value_cansleep(cs42l43->reset, 0); in cs42l43_power_down()
1001 ret = regulator_disable(cs42l43->vdd_p); in cs42l43_power_down()
1003 dev_err(cs42l43->dev, "Failed to disable vdd-p: %d\n", ret); in cs42l43_power_down()
1014 dev_set_drvdata(cs42l43->dev, cs42l43); in cs42l43_dev_probe()
1016 mutex_init(&cs42l43->pll_lock); in cs42l43_dev_probe()
1017 init_completion(&cs42l43->device_attach); in cs42l43_dev_probe()
1018 init_completion(&cs42l43->device_detach); in cs42l43_dev_probe()
1019 init_completion(&cs42l43->firmware_download); in cs42l43_dev_probe()
1020 INIT_WORK(&cs42l43->boot_work, cs42l43_boot_work); in cs42l43_dev_probe()
1022 regcache_cache_only(cs42l43->regmap, true); in cs42l43_dev_probe()
1024 cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW); in cs42l43_dev_probe()
1025 if (IS_ERR(cs42l43->reset)) in cs42l43_dev_probe()
1026 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), in cs42l43_dev_probe()
1027 "Failed to get reset\n"); in cs42l43_dev_probe()
1029 cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); in cs42l43_dev_probe()
1030 if (IS_ERR(cs42l43->vdd_p)) in cs42l43_dev_probe()
1031 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), in cs42l43_dev_probe()
1032 "Failed to get vdd-p\n"); in cs42l43_dev_probe()
1034 cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d"); in cs42l43_dev_probe()
1035 if (IS_ERR(cs42l43->vdd_d)) in cs42l43_dev_probe()
1036 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d), in cs42l43_dev_probe()
1037 "Failed to get vdd-d\n"); in cs42l43_dev_probe()
1042 cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i]; in cs42l43_dev_probe()
1044 ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES, in cs42l43_dev_probe()
1045 cs42l43->core_supplies); in cs42l43_dev_probe()
1047 return dev_err_probe(cs42l43->dev, ret, in cs42l43_dev_probe()
1054 pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME); in cs42l43_dev_probe()
1055 pm_runtime_use_autosuspend(cs42l43->dev); in cs42l43_dev_probe()
1056 pm_runtime_set_active(cs42l43->dev); in cs42l43_dev_probe()
1061 pm_runtime_get_noresume(cs42l43->dev); in cs42l43_dev_probe()
1062 devm_pm_runtime_enable(cs42l43->dev); in cs42l43_dev_probe()
1064 queue_work(system_long_wq, &cs42l43->boot_work); in cs42l43_dev_probe()
1092 dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret); in cs42l43_suspend()
1117 dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); in cs42l43_resume()
1133 regcache_cache_only(cs42l43->regmap, true); in cs42l43_runtime_suspend()
1148 ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary); in cs42l43_runtime_resume()
1150 dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret); in cs42l43_runtime_resume()
1156 * If the canary has cleared the chip has reset, re-handle the in cs42l43_runtime_resume()
1157 * MCU and mark the cache as dirty to indicate the chip reset. in cs42l43_runtime_resume()
1163 regcache_mark_dirty(cs42l43->regmap); in cs42l43_runtime_resume()
1166 ret = regcache_sync(cs42l43->regmap); in cs42l43_runtime_resume()
1168 dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret); in cs42l43_runtime_resume()
1175 regcache_cache_only(cs42l43->regmap, true); in cs42l43_runtime_resume()