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.
17 #include <linux/mfd/cs42l43-regs.h>
22 #include "cs42l43.h"
431 #define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT)
487 .name = "cs42l43",
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",
520 static int cs42l43_soft_reset(struct cs42l43 *cs42l43) in cs42l43_soft_reset() argument
526 reinit_completion(&cs42l43->device_detach); 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
555 static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43) in cs42l43_wait_for_attach() argument
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()
587 static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow) in cs42l43_mcu_stage_2_3() argument
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()
622 static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43) in cs42l43_mcu_stage_3_2() argument
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()
628 return cs42l43_soft_reset(cs42l43); in cs42l43_mcu_stage_3_2()
635 static int cs42l43_mcu_disable(struct cs42l43 *cs42l43) in cs42l43_mcu_disable() argument
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()
656 return cs42l43_soft_reset(cs42l43); in cs42l43_mcu_disable()
664 struct cs42l43 *cs42l43 = context; in cs42l43_mcu_load_firmware() local
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()
703 complete(&cs42l43->firmware_download); in cs42l43_mcu_load_firmware()
709 * require the driver to wait for the device to re-attach on the SoundWire bus,
712 static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) in cs42l43_mcu_update_step() argument
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()
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()
774 GFP_KERNEL, cs42l43, 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()
788 return cs42l43_mcu_stage_2_3(cs42l43, shadow); in cs42l43_mcu_update_step()
792 return cs42l43_mcu_disable(cs42l43); in cs42l43_mcu_update_step()
794 return cs42l43_mcu_stage_3_2(cs42l43); 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()
806 static int cs42l43_mcu_update(struct cs42l43 *cs42l43) in cs42l43_mcu_update() argument
811 ret = cs42l43_mcu_update_step(cs42l43); in cs42l43_mcu_update()
812 if (ret != -EAGAIN) in cs42l43_mcu_update()
815 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_mcu_update()
820 dev_err(cs42l43->dev, "Failed retrying update\n"); in cs42l43_mcu_update()
821 return -ETIMEDOUT; in cs42l43_mcu_update()
824 static int cs42l43_irq_config(struct cs42l43 *cs42l43) in cs42l43_irq_config() argument
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()
873 struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work); in cs42l43_boot_work() local
877 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_boot_work()
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()
910 ret = cs42l43_mcu_update(cs42l43); 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()
921 ret = cs42l43_irq_config(cs42l43); 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()
940 cs42l43_dev_remove(cs42l43); in cs42l43_boot_work()
943 static int cs42l43_power_up(struct cs42l43 *cs42l43) in cs42l43_power_up() argument
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()
983 static int cs42l43_power_down(struct cs42l43 *cs42l43) in cs42l43_power_down() argument
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()
1010 int cs42l43_dev_probe(struct cs42l43 *cs42l43) in cs42l43_dev_probe() argument
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()
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()
1050 ret = cs42l43_power_up(cs42l43); 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()
1070 void cs42l43_dev_remove(struct cs42l43 *cs42l43) in cs42l43_dev_remove() argument
1072 cs42l43_power_down(cs42l43); in cs42l43_dev_remove()
1078 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_suspend() local
1084 * state for the MCU/GPIOs is returned as soon as possible after system in cs42l43_suspend()
1092 dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret); in cs42l43_suspend()
1099 ret = cs42l43_power_down(cs42l43); in cs42l43_suspend()
1108 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_resume() local
1111 ret = cs42l43_power_up(cs42l43); in cs42l43_resume()
1117 dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); in cs42l43_resume()
1126 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_runtime_suspend() local
1133 regcache_cache_only(cs42l43->regmap, true); in cs42l43_runtime_suspend()
1140 struct cs42l43 *cs42l43 = dev_get_drvdata(dev); in cs42l43_runtime_resume() local
1144 ret = cs42l43_wait_for_attach(cs42l43); in cs42l43_runtime_resume()
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()
1159 ret = cs42l43_mcu_update(cs42l43); 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()
1185 MODULE_DESCRIPTION("CS42L43 Core Driver");
1186 MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
1188 MODULE_FIRMWARE("cs42l43.bin");