Lines Matching +full:ec +full:- +full:codec
1 // SPDX-License-Identifier: GPL-2.0
5 * ChromeOS Embedded Controller codec driver.
7 * This driver uses the cros-ec interface to communicate with the ChromeOS
8 * EC for audio function.
73 return priv->ec_capabilities & BIT(cap); in ec_codec_capable()
85 return -ENOMEM; in send_ec_host_command()
87 msg->version = 0; in send_ec_host_command()
88 msg->command = cmd; in send_ec_host_command()
89 msg->outsize = outsize; in send_ec_host_command()
90 msg->insize = insize; in send_ec_host_command()
93 memcpy(msg->data, out, outsize); in send_ec_host_command()
100 memcpy(in, msg->data, insize); in send_ec_host_command()
121 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_get_gain()
126 ucontrol->value.integer.value[0] = r.gain; in dmic_get_gain()
130 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_get_gain()
135 ucontrol->value.integer.value[1] = r.gain; in dmic_get_gain()
148 (struct soc_mixer_control *)kcontrol->private_value; in dmic_put_gain()
149 int max_dmic_gain = control->max; in dmic_put_gain()
150 int left = ucontrol->value.integer.value[0]; in dmic_put_gain()
151 int right = ucontrol->value.integer.value[1]; in dmic_put_gain()
156 return -EINVAL; in dmic_put_gain()
158 dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); in dmic_put_gain()
163 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_put_gain()
171 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_put_gain()
183 SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM,
192 struct device *dev = priv->dev; in dmic_probe()
198 if (!atomic_add_unless(&priv->dmic_probed, 1, 1)) in dmic_probe()
203 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_probe()
215 control->max = r.max_gain; in dmic_probe()
216 control->platform_max = r.max_gain; in dmic_probe()
226 struct snd_soc_component *component = dai->component; in i2s_rx_hw_params()
235 return -EINVAL; in i2s_rx_hw_params()
245 return -EINVAL; in i2s_rx_hw_params()
248 dev_dbg(component->dev, "set depth to %u\n", depth); in i2s_rx_hw_params()
252 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_hw_params()
257 if (priv->i2s_rx_bclk_ratio) in i2s_rx_hw_params()
258 bclk = params_rate(params) * priv->i2s_rx_bclk_ratio; in i2s_rx_hw_params()
262 dev_dbg(component->dev, "set bclk to %u\n", bclk); in i2s_rx_hw_params()
266 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_hw_params()
272 struct snd_soc_component *component = dai->component; in i2s_rx_set_bclk_ratio()
276 priv->i2s_rx_bclk_ratio = ratio; in i2s_rx_set_bclk_ratio()
282 struct snd_soc_component *component = dai->component; in i2s_rx_set_fmt()
292 return -EINVAL; in i2s_rx_set_fmt()
299 return -EINVAL; in i2s_rx_set_fmt()
313 return -EINVAL; in i2s_rx_set_fmt()
316 dev_dbg(component->dev, "set format to %u\n", daifmt); in i2s_rx_set_fmt()
320 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_set_fmt()
334 snd_soc_dapm_to_component(w->dapm); in i2s_rx_event()
341 dev_dbg(component->dev, "enable I2S RX\n"); in i2s_rx_event()
345 dev_dbg(component->dev, "disable I2S RX\n"); in i2s_rx_event()
352 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_event()
369 .name = "EC Codec I2S RX",
404 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
407 dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n"); in wov_map_shm()
411 dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len); in wov_map_shm()
418 return (void __force *)devm_ioremap_wc(priv->dev, in wov_map_shm()
419 r.phys_addr + priv->ec_shm_addr, r.len); in wov_map_shm()
422 dev_err(priv->dev, "unknown status\n"); in wov_map_shm()
427 dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req); in wov_map_shm()
429 if (priv->ap_shm_last_alloc + req > in wov_map_shm()
430 priv->ap_shm_phys_addr + priv->ap_shm_len) { in wov_map_shm()
431 dev_err(priv->dev, "insufficient space for AP SHM\n"); in wov_map_shm()
435 dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n", in wov_map_shm()
436 priv->ap_shm_last_alloc, req); in wov_map_shm()
439 p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc; in wov_map_shm()
442 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
445 dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n"); in wov_map_shm()
450 * Note: EC codec only requests for `r.len' but we allocate in wov_map_shm()
453 offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr; in wov_map_shm()
454 priv->ap_shm_last_alloc += req; in wov_map_shm()
456 return (void *)(uintptr_t)(priv->ap_shm_addr + offset); in wov_map_shm()
464 return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp; in wov_queue_full()
469 if (priv->wov_wp >= priv->wov_rp) in wov_queue_size()
470 return priv->wov_wp - priv->wov_rp; in wov_queue_size()
472 return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp; in wov_queue_size()
477 struct snd_pcm_runtime *runtime = priv->wov_substream->runtime; in wov_queue_dequeue()
481 req = min(len, runtime->dma_bytes - priv->wov_dma_offset); in wov_queue_dequeue()
482 if (priv->wov_wp >= priv->wov_rp) in wov_queue_dequeue()
483 req = min(req, (size_t)priv->wov_wp - priv->wov_rp); in wov_queue_dequeue()
485 req = min(req, sizeof(priv->wov_buf) - priv->wov_rp); in wov_queue_dequeue()
487 memcpy(runtime->dma_area + priv->wov_dma_offset, in wov_queue_dequeue()
488 priv->wov_buf + priv->wov_rp, req); in wov_queue_dequeue()
490 priv->wov_dma_offset += req; in wov_queue_dequeue()
491 if (priv->wov_dma_offset == runtime->dma_bytes) in wov_queue_dequeue()
492 priv->wov_dma_offset = 0; in wov_queue_dequeue()
494 priv->wov_rp += req; in wov_queue_dequeue()
495 if (priv->wov_rp == sizeof(priv->wov_buf)) in wov_queue_dequeue()
496 priv->wov_rp = 0; in wov_queue_dequeue()
498 len -= req; in wov_queue_dequeue()
501 snd_pcm_period_elapsed(priv->wov_substream); in wov_queue_dequeue()
506 size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
510 period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
524 dev_err(priv->dev, "overrun detected\n"); in wov_queue_enqueue()
529 if (priv->wov_wp >= priv->wov_rp) in wov_queue_enqueue()
530 req = sizeof(priv->wov_buf) - priv->wov_wp; in wov_queue_enqueue()
532 /* Note: waste 1-byte to differentiate full and empty */ in wov_queue_enqueue()
533 req = priv->wov_rp - priv->wov_wp - 1; in wov_queue_enqueue()
537 memcpy_fromio(priv->wov_buf + priv->wov_wp, in wov_queue_enqueue()
540 memcpy(priv->wov_buf + priv->wov_wp, addr, req); in wov_queue_enqueue()
542 priv->wov_wp += req; in wov_queue_enqueue()
543 if (priv->wov_wp == sizeof(priv->wov_buf)) in wov_queue_enqueue()
544 priv->wov_wp = 0; in wov_queue_enqueue()
547 len -= req; in wov_queue_enqueue()
560 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio_shm()
564 dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n"); in wov_read_audio_shm()
569 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio_shm()
571 wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len, in wov_read_audio_shm()
572 priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM); in wov_read_audio_shm()
573 return -EAGAIN; in wov_read_audio_shm()
580 int remain = priv->wov_burst_read ? 16000 : 320; in wov_read_audio()
585 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio()
589 dev_err(priv->dev, in wov_read_audio()
595 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio()
596 priv->wov_burst_read = false; in wov_read_audio()
601 remain -= r.len; in wov_read_audio()
604 return -EAGAIN; in wov_read_audio()
613 mutex_lock(&priv->wov_dma_lock); in wov_copy_work()
614 if (!priv->wov_substream) { in wov_copy_work()
615 dev_warn(priv->dev, "no pcm substream\n"); in wov_copy_work()
624 if (ret == -EAGAIN) in wov_copy_work()
625 schedule_delayed_work(&priv->wov_copy_work, in wov_copy_work()
628 dev_err(priv->dev, "failed to read audio data\n"); in wov_copy_work()
630 mutex_unlock(&priv->wov_dma_lock); in wov_copy_work()
639 ucontrol->value.integer.value[0] = priv->wov_enabled; in wov_enable_get()
648 int enabled = ucontrol->value.integer.value[0]; in wov_enable_put()
652 if (priv->wov_enabled != enabled) { in wov_enable_put()
658 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_enable_put()
661 dev_err(priv->dev, "failed to %s wov\n", in wov_enable_put()
666 priv->wov_enabled = enabled; in wov_enable_put()
679 if (size > priv->wov_lang_shm_len) { in wov_set_lang_shm()
680 dev_err(priv->dev, "no enough SHM size: %d\n", in wov_set_lang_shm()
681 priv->wov_lang_shm_len); in wov_set_lang_shm()
682 return -EIO; in wov_set_lang_shm()
685 switch (priv->wov_lang_shm_type) { in wov_set_lang_shm()
687 memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p, in wov_set_lang_shm()
689 memset_io((void __force __iomem *)priv->wov_lang_shm_p + size, in wov_set_lang_shm()
690 0, priv->wov_lang_shm_len - size); in wov_set_lang_shm()
693 memcpy(priv->wov_lang_shm_p, buf, size); in wov_set_lang_shm()
694 memset(priv->wov_lang_shm_p + size, 0, in wov_set_lang_shm()
695 priv->wov_lang_shm_len - size); in wov_set_lang_shm()
703 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang_shm()
704 pp->total_len = size; in wov_set_lang_shm()
705 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang_shm()
708 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n"); in wov_set_lang_shm()
724 req = min(size - i, ARRAY_SIZE(pp->buf)); in wov_set_lang()
727 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang()
728 pp->total_len = size; in wov_set_lang()
729 pp->offset = i; in wov_set_lang()
730 memcpy(pp->buf, buf + i, req); in wov_set_lang()
731 pp->len = req; in wov_set_lang()
732 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang()
735 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n"); in wov_set_lang()
758 size -= 8; in wov_hotword_model_put()
760 dev_dbg(priv->dev, "%s: size=%d\n", __func__, size); in wov_hotword_model_put()
767 dev_dbg(priv->dev, "hash=%*phN\n", SHA256_DIGEST_SIZE, digest); in wov_hotword_model_put()
770 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_hotword_model_put()
777 dev_dbg(priv->dev, "not updated"); in wov_hotword_model_put()
792 SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0,
816 dev_dbg(priv->dev, "%s\n", __func__); in wov_host_event()
818 host_event = cros_ec_get_host_event(priv->ec_device); in wov_host_event()
820 schedule_delayed_work(&priv->wov_copy_work, 0); in wov_host_event()
833 mutex_init(&priv->wov_dma_lock); in wov_probe()
834 INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work); in wov_probe()
836 priv->wov_notifier.notifier_call = wov_host_event; in wov_probe()
838 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_probe()
843 priv->wov_lang_shm_p = wov_map_shm(priv, in wov_probe()
845 &priv->wov_lang_shm_len, in wov_probe()
846 &priv->wov_lang_shm_type); in wov_probe()
847 if (!priv->wov_lang_shm_p) in wov_probe()
848 return -EFAULT; in wov_probe()
852 priv->wov_audio_shm_p = wov_map_shm(priv, in wov_probe()
854 &priv->wov_audio_shm_len, in wov_probe()
855 &priv->wov_audio_shm_type); in wov_probe()
856 if (!priv->wov_audio_shm_p) in wov_probe()
857 return -EFAULT; in wov_probe()
869 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_remove()
900 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_params()
901 priv->wov_substream = substream; in wov_pcm_hw_params()
902 priv->wov_rp = priv->wov_wp = 0; in wov_pcm_hw_params()
903 priv->wov_dma_offset = 0; in wov_pcm_hw_params()
904 priv->wov_burst_read = true; in wov_pcm_hw_params()
905 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_params()
916 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_free()
918 priv->wov_substream = NULL; in wov_pcm_hw_free()
919 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_free()
921 cancel_delayed_work_sync(&priv->wov_copy_work); in wov_pcm_hw_free()
929 struct snd_pcm_runtime *runtime = substream->runtime; in wov_pcm_pointer()
933 return bytes_to_frames(runtime, priv->wov_dma_offset); in wov_pcm_pointer()
939 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, in wov_pcm_new()
958 struct device *dev = &pdev->dev; in cros_ec_codec_platform_probe()
959 struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); in cros_ec_codec_platform_probe()
972 return -ENOMEM; in cros_ec_codec_platform_probe()
975 regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL); in cros_ec_codec_platform_probe()
977 priv->ec_shm_addr = of_read_number(regaddr_p, 2); in cros_ec_codec_platform_probe()
978 priv->ec_shm_len = ec_shm_size; in cros_ec_codec_platform_probe()
981 priv->ec_shm_addr, priv->ec_shm_len); in cros_ec_codec_platform_probe()
984 ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); in cros_ec_codec_platform_probe()
986 priv->ap_shm_phys_addr = res.start; in cros_ec_codec_platform_probe()
987 priv->ap_shm_len = resource_size(&res); in cros_ec_codec_platform_probe()
988 priv->ap_shm_addr = in cros_ec_codec_platform_probe()
990 dev, priv->ap_shm_phys_addr, in cros_ec_codec_platform_probe()
991 priv->ap_shm_len); in cros_ec_codec_platform_probe()
992 priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; in cros_ec_codec_platform_probe()
995 priv->ap_shm_phys_addr, priv->ap_shm_len); in cros_ec_codec_platform_probe()
999 priv->dev = dev; in cros_ec_codec_platform_probe()
1000 priv->ec_device = ec_device; in cros_ec_codec_platform_probe()
1001 atomic_set(&priv->dmic_probed, 0); in cros_ec_codec_platform_probe()
1004 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in cros_ec_codec_platform_probe()
1011 priv->ec_capabilities = r.capabilities; in cros_ec_codec_platform_probe()
1013 /* Reset EC codec i2s rx. */ in cros_ec_codec_platform_probe()
1015 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in cros_ec_codec_platform_probe()
1017 if (ret == -ENOPROTOOPT) { in cros_ec_codec_platform_probe()
1019 "Missing reset command. Please update EC firmware.\n"); in cros_ec_codec_platform_probe()
1038 { .compatible = "google,cros-ec-codec" },
1054 .name = "cros-ec-codec",
1064 MODULE_DESCRIPTION("ChromeOS EC codec driver");
1065 MODULE_AUTHOR("Cheng-Yi Chiang <cychiang@chromium.org>");
1066 MODULE_ALIAS("platform:cros-ec-codec");