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",
402 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
405 dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n"); in wov_map_shm()
409 dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len); in wov_map_shm()
416 return (void __force *)devm_ioremap_wc(priv->dev, in wov_map_shm()
417 r.phys_addr + priv->ec_shm_addr, r.len); in wov_map_shm()
420 dev_err(priv->dev, "unknown status\n"); in wov_map_shm()
425 dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req); in wov_map_shm()
427 if (priv->ap_shm_last_alloc + req > in wov_map_shm()
428 priv->ap_shm_phys_addr + priv->ap_shm_len) { in wov_map_shm()
429 dev_err(priv->dev, "insufficient space for AP SHM\n"); in wov_map_shm()
433 dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n", in wov_map_shm()
434 priv->ap_shm_last_alloc, req); in wov_map_shm()
437 p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc; in wov_map_shm()
440 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in wov_map_shm()
443 dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n"); in wov_map_shm()
448 * Note: EC codec only requests for `r.len' but we allocate in wov_map_shm()
451 offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr; in wov_map_shm()
452 priv->ap_shm_last_alloc += req; in wov_map_shm()
454 return (void *)(uintptr_t)(priv->ap_shm_addr + offset); in wov_map_shm()
462 return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp; in wov_queue_full()
467 if (priv->wov_wp >= priv->wov_rp) in wov_queue_size()
468 return priv->wov_wp - priv->wov_rp; in wov_queue_size()
470 return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp; in wov_queue_size()
475 struct snd_pcm_runtime *runtime = priv->wov_substream->runtime; in wov_queue_dequeue()
479 req = min(len, runtime->dma_bytes - priv->wov_dma_offset); in wov_queue_dequeue()
480 if (priv->wov_wp >= priv->wov_rp) in wov_queue_dequeue()
481 req = min(req, (size_t)priv->wov_wp - priv->wov_rp); in wov_queue_dequeue()
483 req = min(req, sizeof(priv->wov_buf) - priv->wov_rp); in wov_queue_dequeue()
485 memcpy(runtime->dma_area + priv->wov_dma_offset, in wov_queue_dequeue()
486 priv->wov_buf + priv->wov_rp, req); in wov_queue_dequeue()
488 priv->wov_dma_offset += req; in wov_queue_dequeue()
489 if (priv->wov_dma_offset == runtime->dma_bytes) in wov_queue_dequeue()
490 priv->wov_dma_offset = 0; in wov_queue_dequeue()
492 priv->wov_rp += req; in wov_queue_dequeue()
493 if (priv->wov_rp == sizeof(priv->wov_buf)) in wov_queue_dequeue()
494 priv->wov_rp = 0; in wov_queue_dequeue()
496 len -= req; in wov_queue_dequeue()
499 snd_pcm_period_elapsed(priv->wov_substream); in wov_queue_dequeue()
504 size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
508 period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); in wov_queue_try_dequeue()
522 dev_err(priv->dev, "overrun detected\n"); in wov_queue_enqueue()
527 if (priv->wov_wp >= priv->wov_rp) in wov_queue_enqueue()
528 req = sizeof(priv->wov_buf) - priv->wov_wp; in wov_queue_enqueue()
530 /* Note: waste 1-byte to differentiate full and empty */ in wov_queue_enqueue()
531 req = priv->wov_rp - priv->wov_wp - 1; in wov_queue_enqueue()
535 memcpy_fromio(priv->wov_buf + priv->wov_wp, in wov_queue_enqueue()
538 memcpy(priv->wov_buf + priv->wov_wp, addr, req); in wov_queue_enqueue()
540 priv->wov_wp += req; in wov_queue_enqueue()
541 if (priv->wov_wp == sizeof(priv->wov_buf)) in wov_queue_enqueue()
542 priv->wov_wp = 0; in wov_queue_enqueue()
545 len -= req; in wov_queue_enqueue()
558 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio_shm()
562 dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n"); in wov_read_audio_shm()
567 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio_shm()
569 wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len, in wov_read_audio_shm()
570 priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM); in wov_read_audio_shm()
571 return -EAGAIN; in wov_read_audio_shm()
578 int remain = priv->wov_burst_read ? 16000 : 320; in wov_read_audio()
583 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_read_audio()
587 dev_err(priv->dev, in wov_read_audio()
593 dev_dbg(priv->dev, "no data, sleep\n"); in wov_read_audio()
594 priv->wov_burst_read = false; in wov_read_audio()
599 remain -= r.len; in wov_read_audio()
602 return -EAGAIN; in wov_read_audio()
611 mutex_lock(&priv->wov_dma_lock); in wov_copy_work()
612 if (!priv->wov_substream) { in wov_copy_work()
613 dev_warn(priv->dev, "no pcm substream\n"); in wov_copy_work()
622 if (ret == -EAGAIN) in wov_copy_work()
623 schedule_delayed_work(&priv->wov_copy_work, in wov_copy_work()
626 dev_err(priv->dev, "failed to read audio data\n"); in wov_copy_work()
628 mutex_unlock(&priv->wov_dma_lock); in wov_copy_work()
637 ucontrol->value.integer.value[0] = priv->wov_enabled; in wov_enable_get()
646 int enabled = ucontrol->value.integer.value[0]; in wov_enable_put()
650 if (priv->wov_enabled != enabled) { in wov_enable_put()
656 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_enable_put()
659 dev_err(priv->dev, "failed to %s wov\n", in wov_enable_put()
664 priv->wov_enabled = enabled; in wov_enable_put()
677 if (size > priv->wov_lang_shm_len) { in wov_set_lang_shm()
678 dev_err(priv->dev, "no enough SHM size: %d\n", in wov_set_lang_shm()
679 priv->wov_lang_shm_len); in wov_set_lang_shm()
680 return -EIO; in wov_set_lang_shm()
683 switch (priv->wov_lang_shm_type) { in wov_set_lang_shm()
685 memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p, in wov_set_lang_shm()
687 memset_io((void __force __iomem *)priv->wov_lang_shm_p + size, in wov_set_lang_shm()
688 0, priv->wov_lang_shm_len - size); in wov_set_lang_shm()
691 memcpy(priv->wov_lang_shm_p, buf, size); in wov_set_lang_shm()
692 memset(priv->wov_lang_shm_p + size, 0, in wov_set_lang_shm()
693 priv->wov_lang_shm_len - size); in wov_set_lang_shm()
701 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang_shm()
702 pp->total_len = size; in wov_set_lang_shm()
703 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang_shm()
706 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n"); in wov_set_lang_shm()
722 req = min(size - i, ARRAY_SIZE(pp->buf)); in wov_set_lang()
725 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); in wov_set_lang()
726 pp->total_len = size; in wov_set_lang()
727 pp->offset = i; in wov_set_lang()
728 memcpy(pp->buf, buf + i, req); in wov_set_lang()
729 pp->len = req; in wov_set_lang()
730 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_set_lang()
733 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n"); in wov_set_lang()
756 size -= 8; in wov_hotword_model_put()
758 dev_dbg(priv->dev, "%s: size=%d\n", __func__, size); in wov_hotword_model_put()
765 dev_dbg(priv->dev, "hash=%*phN\n", SHA256_DIGEST_SIZE, digest); in wov_hotword_model_put()
768 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, in wov_hotword_model_put()
775 dev_dbg(priv->dev, "not updated"); in wov_hotword_model_put()
790 SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0,
814 dev_dbg(priv->dev, "%s\n", __func__); in wov_host_event()
816 host_event = cros_ec_get_host_event(priv->ec_device); in wov_host_event()
818 schedule_delayed_work(&priv->wov_copy_work, 0); in wov_host_event()
831 mutex_init(&priv->wov_dma_lock); in wov_probe()
832 INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work); in wov_probe()
834 priv->wov_notifier.notifier_call = wov_host_event; in wov_probe()
836 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_probe()
841 priv->wov_lang_shm_p = wov_map_shm(priv, in wov_probe()
843 &priv->wov_lang_shm_len, in wov_probe()
844 &priv->wov_lang_shm_type); in wov_probe()
845 if (!priv->wov_lang_shm_p) in wov_probe()
846 return -EFAULT; in wov_probe()
850 priv->wov_audio_shm_p = wov_map_shm(priv, in wov_probe()
852 &priv->wov_audio_shm_len, in wov_probe()
853 &priv->wov_audio_shm_type); in wov_probe()
854 if (!priv->wov_audio_shm_p) in wov_probe()
855 return -EFAULT; in wov_probe()
867 &priv->ec_device->event_notifier, &priv->wov_notifier); in wov_remove()
898 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_params()
899 priv->wov_substream = substream; in wov_pcm_hw_params()
900 priv->wov_rp = priv->wov_wp = 0; in wov_pcm_hw_params()
901 priv->wov_dma_offset = 0; in wov_pcm_hw_params()
902 priv->wov_burst_read = true; in wov_pcm_hw_params()
903 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_params()
914 mutex_lock(&priv->wov_dma_lock); in wov_pcm_hw_free()
916 priv->wov_substream = NULL; in wov_pcm_hw_free()
917 mutex_unlock(&priv->wov_dma_lock); in wov_pcm_hw_free()
919 cancel_delayed_work_sync(&priv->wov_copy_work); in wov_pcm_hw_free()
927 struct snd_pcm_runtime *runtime = substream->runtime; in wov_pcm_pointer()
931 return bytes_to_frames(runtime, priv->wov_dma_offset); in wov_pcm_pointer()
937 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, in wov_pcm_new()
956 struct device *dev = &pdev->dev; in cros_ec_codec_platform_probe()
957 struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); in cros_ec_codec_platform_probe()
971 return -ENOMEM; in cros_ec_codec_platform_probe()
974 regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL); in cros_ec_codec_platform_probe()
976 priv->ec_shm_addr = of_read_number(regaddr_p, 2); in cros_ec_codec_platform_probe()
977 priv->ec_shm_len = ec_shm_size; in cros_ec_codec_platform_probe()
980 priv->ec_shm_addr, priv->ec_shm_len); in cros_ec_codec_platform_probe()
983 node = of_parse_phandle(dev->of_node, "memory-region", 0); in cros_ec_codec_platform_probe()
987 priv->ap_shm_phys_addr = res.start; in cros_ec_codec_platform_probe()
988 priv->ap_shm_len = resource_size(&res); in cros_ec_codec_platform_probe()
989 priv->ap_shm_addr = in cros_ec_codec_platform_probe()
991 dev, priv->ap_shm_phys_addr, in cros_ec_codec_platform_probe()
992 priv->ap_shm_len); in cros_ec_codec_platform_probe()
993 priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; in cros_ec_codec_platform_probe()
996 priv->ap_shm_phys_addr, priv->ap_shm_len); in cros_ec_codec_platform_probe()
1002 priv->dev = dev; in cros_ec_codec_platform_probe()
1003 priv->ec_device = ec_device; in cros_ec_codec_platform_probe()
1004 atomic_set(&priv->dmic_probed, 0); in cros_ec_codec_platform_probe()
1007 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, in cros_ec_codec_platform_probe()
1014 priv->ec_capabilities = r.capabilities; in cros_ec_codec_platform_probe()
1016 /* Reset EC codec i2s rx. */ in cros_ec_codec_platform_probe()
1018 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, in cros_ec_codec_platform_probe()
1020 if (ret == -ENOPROTOOPT) { in cros_ec_codec_platform_probe()
1022 "Missing reset command. Please update EC firmware.\n"); in cros_ec_codec_platform_probe()
1041 { .compatible = "google,cros-ec-codec" },
1057 .name = "cros-ec-codec",
1067 MODULE_DESCRIPTION("ChromeOS EC codec driver");
1068 MODULE_AUTHOR("Cheng-Yi Chiang <cychiang@chromium.org>");
1069 MODULE_ALIAS("platform:cros-ec-codec");