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.
71 return priv->ec_capabilities & BIT(cap); in ec_codec_capable()
83 return -ENOMEM; in send_ec_host_command()
85 msg->version = 0; in send_ec_host_command()
86 msg->command = cmd; in send_ec_host_command()
87 msg->outsize = outsize; in send_ec_host_command()
88 msg->insize = insize; in send_ec_host_command()
91 memcpy(msg->data, out, outsize); in send_ec_host_command()
98 memcpy(in, msg->data, insize); in send_ec_host_command()
119 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_get_gain()
124 ucontrol->value.integer.value[0] = r.gain; in dmic_get_gain()
128 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_get_gain()
133 ucontrol->value.integer.value[1] = r.gain; in dmic_get_gain()
146 (struct soc_mixer_control *)kcontrol->private_value; in dmic_put_gain()
147 int max_dmic_gain = control->max; in dmic_put_gain()
148 int left = ucontrol->value.integer.value[0]; in dmic_put_gain()
149 int right = ucontrol->value.integer.value[1]; in dmic_put_gain()
154 return -EINVAL; in dmic_put_gain()
156 dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); in dmic_put_gain()
161 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_put_gain()
169 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_put_gain()
181 SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM,
190 struct device *dev = priv->dev; in dmic_probe()
196 if (!atomic_add_unless(&priv->dmic_probed, 1, 1)) in dmic_probe()
201 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, in dmic_probe()
213 control->max = r.max_gain; in dmic_probe()
214 control->platform_max = r.max_gain; in dmic_probe()
224 struct snd_soc_component *component = dai->component; in i2s_rx_hw_params()
233 return -EINVAL; in i2s_rx_hw_params()
243 return -EINVAL; in i2s_rx_hw_params()
246 dev_dbg(component->dev, "set depth to %u\n", depth); in i2s_rx_hw_params()
250 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_hw_params()
255 if (priv->i2s_rx_bclk_ratio) in i2s_rx_hw_params()
256 bclk = params_rate(params) * priv->i2s_rx_bclk_ratio; in i2s_rx_hw_params()
260 dev_dbg(component->dev, "set bclk to %u\n", bclk); in i2s_rx_hw_params()
264 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_hw_params()
270 struct snd_soc_component *component = dai->component; in i2s_rx_set_bclk_ratio()
274 priv->i2s_rx_bclk_ratio = ratio; in i2s_rx_set_bclk_ratio()
280 struct snd_soc_component *component = dai->component; in i2s_rx_set_fmt()
290 return -EINVAL; in i2s_rx_set_fmt()
297 return -EINVAL; in i2s_rx_set_fmt()
311 return -EINVAL; in i2s_rx_set_fmt()
314 dev_dbg(component->dev, "set format to %u\n", daifmt); in i2s_rx_set_fmt()
318 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_set_fmt()
332 snd_soc_dapm_to_component(w->dapm); in i2s_rx_event()
339 dev_dbg(component->dev, "enable I2S RX\n"); in i2s_rx_event()
343 dev_dbg(component->dev, "disable I2S RX\n"); in i2s_rx_event()
350 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in i2s_rx_event()
367 .name = "EC Codec I2S RX",
401 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
404 dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n"); in wov_map_shm()
408 dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len); in wov_map_shm()
415 return (void __force *)devm_ioremap_wc(priv->dev, in wov_map_shm()
416 r.phys_addr + priv->ec_shm_addr, r.len); in wov_map_shm()
419 dev_err(priv->dev, "unknown status\n"); in wov_map_shm()
424 dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req); in wov_map_shm()
426 if (priv->ap_shm_last_alloc + req > in wov_map_shm()
427 priv->ap_shm_phys_addr + priv->ap_shm_len) { in wov_map_shm()
428 dev_err(priv->dev, "insufficient space for AP SHM\n"); in wov_map_shm()
432 dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n", in wov_map_shm()
433 priv->ap_shm_last_alloc, req); in wov_map_shm()
436 p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc; in wov_map_shm()
439 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
442 dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n"); in wov_map_shm()
447 * Note: EC codec only requests for `r.len' but we allocate in wov_map_shm()
450 offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr; in wov_map_shm()
451 priv->ap_shm_last_alloc += req; in wov_map_shm()
453 return (void *)(uintptr_t)(priv->ap_shm_addr + offset); in wov_map_shm()
461 return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp; in wov_queue_full()
466 if (priv->wov_wp >= priv->wov_rp) in wov_queue_size()
467 return priv->wov_wp - priv->wov_rp; in wov_queue_size()
469 return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp; in wov_queue_size()
474 struct snd_pcm_runtime *runtime = priv->wov_substream->runtime; in wov_queue_dequeue()
478 req = min(len, runtime->dma_bytes - priv->wov_dma_offset); in wov_queue_dequeue()
479 if (priv->wov_wp >= priv->wov_rp) in wov_queue_dequeue()
480 req = min(req, (size_t)priv->wov_wp - priv->wov_rp); in wov_queue_dequeue()
482 req = min(req, sizeof(priv->wov_buf) - priv->wov_rp); in wov_queue_dequeue()
484 memcpy(runtime->dma_area + priv->wov_dma_offset, in wov_queue_dequeue()
485 priv->wov_buf + priv->wov_rp, req); in wov_queue_dequeue()
487 priv->wov_dma_offset += req; in wov_queue_dequeue()
488 if (priv->wov_dma_offset == runtime->dma_bytes) in wov_queue_dequeue()
489 priv->wov_dma_offset = 0; in wov_queue_dequeue()
491 priv->wov_rp += req; in wov_queue_dequeue()
492 if (priv->wov_rp == sizeof(priv->wov_buf)) in wov_queue_dequeue()
493 priv->wov_rp = 0; in wov_queue_dequeue()
495 len -= req; in wov_queue_dequeue()
498 snd_pcm_period_elapsed(priv->wov_substream); in wov_queue_dequeue()
503 size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
507 period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
521 dev_err(priv->dev, "overrun detected\n"); in wov_queue_enqueue()
526 if (priv->wov_wp >= priv->wov_rp) in wov_queue_enqueue()
527 req = sizeof(priv->wov_buf) - priv->wov_wp; in wov_queue_enqueue()
529 /* Note: waste 1-byte to differentiate full and empty */ in wov_queue_enqueue()
530 req = priv->wov_rp - priv->wov_wp - 1; in wov_queue_enqueue()
534 memcpy_fromio(priv->wov_buf + priv->wov_wp, in wov_queue_enqueue()
537 memcpy(priv->wov_buf + priv->wov_wp, addr, req); in wov_queue_enqueue()
539 priv->wov_wp += req; in wov_queue_enqueue()
540 if (priv->wov_wp == sizeof(priv->wov_buf)) in wov_queue_enqueue()
541 priv->wov_wp = 0; in wov_queue_enqueue()
544 len -= req; in wov_queue_enqueue()
557 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio_shm()
561 dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n"); in wov_read_audio_shm()
566 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio_shm()
568 wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len, in wov_read_audio_shm()
569 priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM); in wov_read_audio_shm()
570 return -EAGAIN; in wov_read_audio_shm()
577 int remain = priv->wov_burst_read ? 16000 : 320; in wov_read_audio()
582 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio()
586 dev_err(priv->dev, in wov_read_audio()
592 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio()
593 priv->wov_burst_read = false; in wov_read_audio()
598 remain -= r.len; in wov_read_audio()
601 return -EAGAIN; in wov_read_audio()
610 mutex_lock(&priv->wov_dma_lock); in wov_copy_work()
611 if (!priv->wov_substream) { in wov_copy_work()
612 dev_warn(priv->dev, "no pcm substream\n"); in wov_copy_work()
621 if (ret == -EAGAIN) in wov_copy_work()
622 schedule_delayed_work(&priv->wov_copy_work, in wov_copy_work()
625 dev_err(priv->dev, "failed to read audio data\n"); in wov_copy_work()
627 mutex_unlock(&priv->wov_dma_lock); in wov_copy_work()
636 ucontrol->value.integer.value[0] = priv->wov_enabled; in wov_enable_get()
645 int enabled = ucontrol->value.integer.value[0]; in wov_enable_put()
649 if (priv->wov_enabled != enabled) { in wov_enable_put()
655 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_enable_put()
658 dev_err(priv->dev, "failed to %s wov\n", in wov_enable_put()
663 priv->wov_enabled = enabled; in wov_enable_put()
676 if (size > priv->wov_lang_shm_len) { in wov_set_lang_shm()
677 dev_err(priv->dev, "no enough SHM size: %d\n", in wov_set_lang_shm()
678 priv->wov_lang_shm_len); in wov_set_lang_shm()
679 return -EIO; in wov_set_lang_shm()
682 switch (priv->wov_lang_shm_type) { in wov_set_lang_shm()
684 memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p, in wov_set_lang_shm()
686 memset_io((void __force __iomem *)priv->wov_lang_shm_p + size, in wov_set_lang_shm()
687 0, priv->wov_lang_shm_len - size); in wov_set_lang_shm()
690 memcpy(priv->wov_lang_shm_p, buf, size); in wov_set_lang_shm()
691 memset(priv->wov_lang_shm_p + size, 0, in wov_set_lang_shm()
692 priv->wov_lang_shm_len - size); in wov_set_lang_shm()
700 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang_shm()
701 pp->total_len = size; in wov_set_lang_shm()
702 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang_shm()
705 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n"); in wov_set_lang_shm()
721 req = min(size - i, ARRAY_SIZE(pp->buf)); in wov_set_lang()
724 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang()
725 pp->total_len = size; in wov_set_lang()
726 pp->offset = i; in wov_set_lang()
727 memcpy(pp->buf, buf + i, req); in wov_set_lang()
728 pp->len = req; in wov_set_lang()
729 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang()
732 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n"); in wov_set_lang()
755 size -= 8; in wov_hotword_model_put()
757 dev_dbg(priv->dev, "%s: size=%d\n", __func__, size); in wov_hotword_model_put()
764 dev_dbg(priv->dev, "hash=%*phN\n", SHA256_DIGEST_SIZE, digest); in wov_hotword_model_put()
767 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_hotword_model_put()
774 dev_dbg(priv->dev, "not updated"); in wov_hotword_model_put()
789 SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0,
813 dev_dbg(priv->dev, "%s\n", __func__); in wov_host_event()
815 host_event = cros_ec_get_host_event(priv->ec_device); in wov_host_event()
817 schedule_delayed_work(&priv->wov_copy_work, 0); in wov_host_event()
830 mutex_init(&priv->wov_dma_lock); in wov_probe()
831 INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work); in wov_probe()
833 priv->wov_notifier.notifier_call = wov_host_event; in wov_probe()
835 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_probe()
840 priv->wov_lang_shm_p = wov_map_shm(priv, in wov_probe()
842 &priv->wov_lang_shm_len, in wov_probe()
843 &priv->wov_lang_shm_type); in wov_probe()
844 if (!priv->wov_lang_shm_p) in wov_probe()
845 return -EFAULT; in wov_probe()
849 priv->wov_audio_shm_p = wov_map_shm(priv, in wov_probe()
851 &priv->wov_audio_shm_len, in wov_probe()
852 &priv->wov_audio_shm_type); in wov_probe()
853 if (!priv->wov_audio_shm_p) in wov_probe()
854 return -EFAULT; in wov_probe()
866 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_remove()
897 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_params()
898 priv->wov_substream = substream; in wov_pcm_hw_params()
899 priv->wov_rp = priv->wov_wp = 0; in wov_pcm_hw_params()
900 priv->wov_dma_offset = 0; in wov_pcm_hw_params()
901 priv->wov_burst_read = true; in wov_pcm_hw_params()
902 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_params()
913 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_free()
915 priv->wov_substream = NULL; in wov_pcm_hw_free()
916 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_free()
918 cancel_delayed_work_sync(&priv->wov_copy_work); in wov_pcm_hw_free()
926 struct snd_pcm_runtime *runtime = substream->runtime; in wov_pcm_pointer()
930 return bytes_to_frames(runtime, priv->wov_dma_offset); in wov_pcm_pointer()
936 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, in wov_pcm_new()
955 struct device *dev = &pdev->dev; in cros_ec_codec_platform_probe()
956 struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); in cros_ec_codec_platform_probe()
970 return -ENOMEM; in cros_ec_codec_platform_probe()
973 regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL); in cros_ec_codec_platform_probe()
975 priv->ec_shm_addr = of_read_number(regaddr_p, 2); in cros_ec_codec_platform_probe()
976 priv->ec_shm_len = ec_shm_size; in cros_ec_codec_platform_probe()
979 priv->ec_shm_addr, priv->ec_shm_len); in cros_ec_codec_platform_probe()
982 node = of_parse_phandle(dev->of_node, "memory-region", 0); 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()
1000 priv->dev = dev; in cros_ec_codec_platform_probe()
1001 priv->ec_device = ec_device; in cros_ec_codec_platform_probe()
1002 atomic_set(&priv->dmic_probed, 0); in cros_ec_codec_platform_probe()
1005 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in cros_ec_codec_platform_probe()
1012 priv->ec_capabilities = r.capabilities; in cros_ec_codec_platform_probe()
1014 /* Reset EC codec i2s rx. */ in cros_ec_codec_platform_probe()
1016 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in cros_ec_codec_platform_probe()
1018 if (ret == -ENOPROTOOPT) { in cros_ec_codec_platform_probe()
1020 "Missing reset command. Please update EC firmware.\n"); in cros_ec_codec_platform_probe()
1039 { .compatible = "google,cros-ec-codec" },
1055 .name = "cros-ec-codec",
1065 MODULE_DESCRIPTION("ChromeOS EC codec driver");
1066 MODULE_AUTHOR("Cheng-Yi Chiang <cychiang@chromium.org>");
1067 MODULE_ALIAS("platform:cros-ec-codec");