Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 Google, Inc.
4 *
5 * ChromeOS Embedded Controller codec driver.
6 *
7 * This driver uses the cros-ec interface to communicate with the ChromeOS
8 * EC for audio function.
9 */
10
11#include <crypto/hash.h>
12#include <crypto/sha.h>
13#include <linux/acpi.h>
14#include <linux/delay.h>
15#include <linux/device.h>
16#include <linux/io.h>
17#include <linux/jiffies.h>
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/platform_data/cros_ec_commands.h>
23#include <linux/platform_data/cros_ec_proto.h>
24#include <linux/platform_device.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/tlv.h>
29
30struct cros_ec_codec_priv {
31 struct device *dev;
32 struct cros_ec_device *ec_device;
33
34 /* common */
35 uint32_t ec_capabilities;
36
37 uint64_t ec_shm_addr;
38 uint32_t ec_shm_len;
39
40 uint64_t ap_shm_phys_addr;
41 uint32_t ap_shm_len;
42 uint64_t ap_shm_addr;
43 uint64_t ap_shm_last_alloc;
44
45 /* DMIC */
46 atomic_t dmic_probed;
47
48 /* I2S_RX */
49 uint32_t i2s_rx_bclk_ratio;
50
51 /* WoV */
52 bool wov_enabled;
53 uint8_t *wov_audio_shm_p;
54 uint32_t wov_audio_shm_len;
55 uint8_t wov_audio_shm_type;
56 uint8_t *wov_lang_shm_p;
57 uint32_t wov_lang_shm_len;
58 uint8_t wov_lang_shm_type;
59
60 struct mutex wov_dma_lock;
61 uint8_t wov_buf[64000];
62 uint32_t wov_rp, wov_wp;
63 size_t wov_dma_offset;
64 bool wov_burst_read;
65 struct snd_pcm_substream *wov_substream;
66 struct delayed_work wov_copy_work;
67 struct notifier_block wov_notifier;
68};
69
70static int ec_codec_capable(struct cros_ec_codec_priv *priv, uint8_t cap)
71{
72 return priv->ec_capabilities & BIT(cap);
73}
74
75static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd,
76 uint8_t *out, size_t outsize,
77 uint8_t *in, size_t insize)
78{
79 int ret;
80 struct cros_ec_command *msg;
81
82 msg = kmalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
83 if (!msg)
84 return -ENOMEM;
85
86 msg->version = 0;
87 msg->command = cmd;
88 msg->outsize = outsize;
89 msg->insize = insize;
90
91 if (outsize)
92 memcpy(msg->data, out, outsize);
93
94 ret = cros_ec_cmd_xfer_status(ec_dev, msg);
95 if (ret < 0)
96 goto error;
97
98 if (insize)
99 memcpy(in, msg->data, insize);
100
101 ret = 0;
102error:
103 kfree(msg);
104 return ret;
105}
106
107static int calculate_sha256(struct cros_ec_codec_priv *priv,
108 uint8_t *buf, uint32_t size, uint8_t *digest)
109{
110 struct crypto_shash *tfm;
111
112 tfm = crypto_alloc_shash("sha256", CRYPTO_ALG_TYPE_SHASH, 0);
113 if (IS_ERR(tfm)) {
114 dev_err(priv->dev, "can't alloc shash\n");
115 return PTR_ERR(tfm);
116 }
117
118 {
119 SHASH_DESC_ON_STACK(desc, tfm);
120
121 desc->tfm = tfm;
122
123 crypto_shash_digest(desc, buf, size, digest);
124 shash_desc_zero(desc);
125 }
126
127 crypto_free_shash(tfm);
128
129#ifdef DEBUG
130 {
131 char digest_str[65];
132
133 bin2hex(digest_str, digest, 32);
134 digest_str[64] = 0;
135 dev_dbg(priv->dev, "hash=%s\n", digest_str);
136 }
137#endif
138
139 return 0;
140}
141
142static int dmic_get_gain(struct snd_kcontrol *kcontrol,
143 struct snd_ctl_elem_value *ucontrol)
144{
145 struct snd_soc_component *component =
146 snd_soc_kcontrol_component(kcontrol);
147 struct cros_ec_codec_priv *priv =
148 snd_soc_component_get_drvdata(component);
149 struct ec_param_ec_codec_dmic p;
150 struct ec_response_ec_codec_dmic_get_gain_idx r;
151 int ret;
152
153 p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX;
154 p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0;
155 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC,
156 (uint8_t *)&p, sizeof(p),
157 (uint8_t *)&r, sizeof(r));
158 if (ret < 0)
159 return ret;
160 ucontrol->value.integer.value[0] = r.gain;
161
162 p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX;
163 p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1;
164 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC,
165 (uint8_t *)&p, sizeof(p),
166 (uint8_t *)&r, sizeof(r));
167 if (ret < 0)
168 return ret;
169 ucontrol->value.integer.value[1] = r.gain;
170
171 return 0;
172}
173
174static int dmic_put_gain(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
176{
177 struct snd_soc_component *component =
178 snd_soc_kcontrol_component(kcontrol);
179 struct cros_ec_codec_priv *priv =
180 snd_soc_component_get_drvdata(component);
181 struct soc_mixer_control *control =
182 (struct soc_mixer_control *)kcontrol->private_value;
183 int max_dmic_gain = control->max;
184 int left = ucontrol->value.integer.value[0];
185 int right = ucontrol->value.integer.value[1];
186 struct ec_param_ec_codec_dmic p;
187 int ret;
188
189 if (left > max_dmic_gain || right > max_dmic_gain)
190 return -EINVAL;
191
192 dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right);
193
194 p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX;
195 p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0;
196 p.set_gain_idx_param.gain = left;
197 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC,
198 (uint8_t *)&p, sizeof(p), NULL, 0);
199 if (ret < 0)
200 return ret;
201
202 p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX;
203 p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1;
204 p.set_gain_idx_param.gain = right;
205 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC,
206 (uint8_t *)&p, sizeof(p), NULL, 0);
207}
208
209static const DECLARE_TLV_DB_SCALE(dmic_gain_tlv, 0, 100, 0);
210
211enum {
212 DMIC_CTL_GAIN = 0,
213};
214
215static struct snd_kcontrol_new dmic_controls[] = {
216 [DMIC_CTL_GAIN] =
217 SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM,
218 0, 0, 0, dmic_get_gain, dmic_put_gain,
219 dmic_gain_tlv),
220};
221
222static int dmic_probe(struct snd_soc_component *component)
223{
224 struct cros_ec_codec_priv *priv =
225 snd_soc_component_get_drvdata(component);
226 struct device *dev = priv->dev;
227 struct soc_mixer_control *control;
228 struct ec_param_ec_codec_dmic p;
229 struct ec_response_ec_codec_dmic_get_max_gain r;
230 int ret;
231
232 if (!atomic_add_unless(&priv->dmic_probed, 1, 1))
233 return 0;
234
235 p.cmd = EC_CODEC_DMIC_GET_MAX_GAIN;
236
237 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC,
238 (uint8_t *)&p, sizeof(p),
239 (uint8_t *)&r, sizeof(r));
240 if (ret < 0) {
241 dev_warn(dev, "get_max_gain() unsupported\n");
242 return 0;
243 }
244
245 dev_dbg(dev, "max gain = %d\n", r.max_gain);
246
247 control = (struct soc_mixer_control *)
248 dmic_controls[DMIC_CTL_GAIN].private_value;
249 control->max = r.max_gain;
250 control->platform_max = r.max_gain;
251
252 return snd_soc_add_component_controls(component,
253 &dmic_controls[DMIC_CTL_GAIN], 1);
254}
255
256static int i2s_rx_hw_params(struct snd_pcm_substream *substream,
257 struct snd_pcm_hw_params *params,
258 struct snd_soc_dai *dai)
259{
260 struct snd_soc_component *component = dai->component;
261 struct cros_ec_codec_priv *priv =
262 snd_soc_component_get_drvdata(component);
263 struct ec_param_ec_codec_i2s_rx p;
264 enum ec_codec_i2s_rx_sample_depth depth;
265 uint32_t bclk;
266 int ret;
267
268 if (params_rate(params) != 48000)
269 return -EINVAL;
270
271 switch (params_format(params)) {
272 case SNDRV_PCM_FORMAT_S16_LE:
273 depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_16;
274 break;
275 case SNDRV_PCM_FORMAT_S24_LE:
276 depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_24;
277 break;
278 default:
279 return -EINVAL;
280 }
281
282 dev_dbg(component->dev, "set depth to %u\n", depth);
283
284 p.cmd = EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH;
285 p.set_sample_depth_param.depth = depth;
286 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
287 (uint8_t *)&p, sizeof(p), NULL, 0);
288 if (ret < 0)
289 return ret;
290
291 if (priv->i2s_rx_bclk_ratio)
292 bclk = params_rate(params) * priv->i2s_rx_bclk_ratio;
293 else
294 bclk = snd_soc_params_to_bclk(params);
295
296 dev_dbg(component->dev, "set bclk to %u\n", bclk);
297
298 p.cmd = EC_CODEC_I2S_RX_SET_BCLK;
299 p.set_bclk_param.bclk = bclk;
300 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
301 (uint8_t *)&p, sizeof(p), NULL, 0);
302}
303
304static int i2s_rx_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
305{
306 struct snd_soc_component *component = dai->component;
307 struct cros_ec_codec_priv *priv =
308 snd_soc_component_get_drvdata(component);
309
310 priv->i2s_rx_bclk_ratio = ratio;
311 return 0;
312}
313
314static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
315{
316 struct snd_soc_component *component = dai->component;
317 struct cros_ec_codec_priv *priv =
318 snd_soc_component_get_drvdata(component);
319 struct ec_param_ec_codec_i2s_rx p;
320 enum ec_codec_i2s_rx_daifmt daifmt;
321
322 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
323 case SND_SOC_DAIFMT_CBS_CFS:
324 break;
325 default:
326 return -EINVAL;
327 }
328
329 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
330 case SND_SOC_DAIFMT_NB_NF:
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
337 case SND_SOC_DAIFMT_I2S:
338 daifmt = EC_CODEC_I2S_RX_DAIFMT_I2S;
339 break;
340 case SND_SOC_DAIFMT_RIGHT_J:
341 daifmt = EC_CODEC_I2S_RX_DAIFMT_RIGHT_J;
342 break;
343 case SND_SOC_DAIFMT_LEFT_J:
344 daifmt = EC_CODEC_I2S_RX_DAIFMT_LEFT_J;
345 break;
346 default:
347 return -EINVAL;
348 }
349
350 dev_dbg(component->dev, "set format to %u\n", daifmt);
351
352 p.cmd = EC_CODEC_I2S_RX_SET_DAIFMT;
353 p.set_daifmt_param.daifmt = daifmt;
354 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
355 (uint8_t *)&p, sizeof(p), NULL, 0);
356}
357
358static const struct snd_soc_dai_ops i2s_rx_dai_ops = {
359 .hw_params = i2s_rx_hw_params,
360 .set_fmt = i2s_rx_set_fmt,
361 .set_bclk_ratio = i2s_rx_set_bclk_ratio,
362};
363
364static int i2s_rx_event(struct snd_soc_dapm_widget *w,
365 struct snd_kcontrol *kcontrol, int event)
366{
367 struct snd_soc_component *component =
368 snd_soc_dapm_to_component(w->dapm);
369 struct cros_ec_codec_priv *priv =
370 snd_soc_component_get_drvdata(component);
371 struct ec_param_ec_codec_i2s_rx p;
372
373 switch (event) {
374 case SND_SOC_DAPM_PRE_PMU:
375 dev_dbg(component->dev, "enable I2S RX\n");
376 p.cmd = EC_CODEC_I2S_RX_ENABLE;
377 break;
378 case SND_SOC_DAPM_PRE_PMD:
379 dev_dbg(component->dev, "disable I2S RX\n");
380 p.cmd = EC_CODEC_I2S_RX_DISABLE;
381 break;
382 default:
383 return 0;
384 }
385
386 return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX,
387 (uint8_t *)&p, sizeof(p), NULL, 0);
388}
389
390static struct snd_soc_dapm_widget i2s_rx_dapm_widgets[] = {
391 SND_SOC_DAPM_INPUT("DMIC"),
392 SND_SOC_DAPM_SUPPLY("I2S RX Enable", SND_SOC_NOPM, 0, 0, i2s_rx_event,
393 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
394 SND_SOC_DAPM_AIF_OUT("I2S RX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0),
395};
396
397static struct snd_soc_dapm_route i2s_rx_dapm_routes[] = {
398 {"I2S RX", NULL, "DMIC"},
399 {"I2S RX", NULL, "I2S RX Enable"},
400};
401
402static struct snd_soc_dai_driver i2s_rx_dai_driver = {
403 .name = "EC Codec I2S RX",
404 .capture = {
405 .stream_name = "I2S Capture",
406 .channels_min = 2,
407 .channels_max = 2,
408 .rates = SNDRV_PCM_RATE_48000,
409 .formats = SNDRV_PCM_FMTBIT_S16_LE |
410 SNDRV_PCM_FMTBIT_S24_LE,
411 },
412 .ops = &i2s_rx_dai_ops,
413};
414
415static int i2s_rx_probe(struct snd_soc_component *component)
416{
417 return dmic_probe(component);
418}
419
420static const struct snd_soc_component_driver i2s_rx_component_driver = {
421 .probe = i2s_rx_probe,
422 .dapm_widgets = i2s_rx_dapm_widgets,
423 .num_dapm_widgets = ARRAY_SIZE(i2s_rx_dapm_widgets),
424 .dapm_routes = i2s_rx_dapm_routes,
425 .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes),
426};
427
428static void *wov_map_shm(struct cros_ec_codec_priv *priv,
429 uint8_t shm_id, uint32_t *len, uint8_t *type)
430{
431 struct ec_param_ec_codec p;
432 struct ec_response_ec_codec_get_shm_addr r;
433 uint32_t req, offset;
434
435 p.cmd = EC_CODEC_GET_SHM_ADDR;
436 p.get_shm_addr_param.shm_id = shm_id;
437 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC,
438 (uint8_t *)&p, sizeof(p),
439 (uint8_t *)&r, sizeof(r)) < 0) {
440 dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n");
441 return NULL;
442 }
443
444 dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len);
445
446 *len = r.len;
447 *type = r.type;
448
449 switch (r.type) {
450 case EC_CODEC_SHM_TYPE_EC_RAM:
451 return (void __force *)devm_ioremap_wc(priv->dev,
452 r.phys_addr + priv->ec_shm_addr, r.len);
453 case EC_CODEC_SHM_TYPE_SYSTEM_RAM:
454 if (r.phys_addr) {
455 dev_err(priv->dev, "unknown status\n");
456 return NULL;
457 }
458
459 req = round_up(r.len, PAGE_SIZE);
460 dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req);
461
462 if (priv->ap_shm_last_alloc + req >
463 priv->ap_shm_phys_addr + priv->ap_shm_len) {
464 dev_err(priv->dev, "insufficient space for AP SHM\n");
465 return NULL;
466 }
467
468 dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n",
469 priv->ap_shm_last_alloc, req);
470
471 p.cmd = EC_CODEC_SET_SHM_ADDR;
472 p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc;
473 p.set_shm_addr_param.len = req;
474 p.set_shm_addr_param.shm_id = shm_id;
475 if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC,
476 (uint8_t *)&p, sizeof(p),
477 NULL, 0) < 0) {
478 dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n");
479 return NULL;
480 }
481
482 /*
483 * Note: EC codec only requests for `r.len' but we allocate
484 * round up PAGE_SIZE `req'.
485 */
486 offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr;
487 priv->ap_shm_last_alloc += req;
488
489 return (void *)(uintptr_t)(priv->ap_shm_addr + offset);
490 default:
491 return NULL;
492 }
493}
494
495static bool wov_queue_full(struct cros_ec_codec_priv *priv)
496{
497 return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp;
498}
499
500static size_t wov_queue_size(struct cros_ec_codec_priv *priv)
501{
502 if (priv->wov_wp >= priv->wov_rp)
503 return priv->wov_wp - priv->wov_rp;
504 else
505 return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp;
506}
507
508static void wov_queue_dequeue(struct cros_ec_codec_priv *priv, size_t len)
509{
510 struct snd_pcm_runtime *runtime = priv->wov_substream->runtime;
511 size_t req;
512
513 while (len) {
514 req = min(len, runtime->dma_bytes - priv->wov_dma_offset);
515 if (priv->wov_wp >= priv->wov_rp)
516 req = min(req, (size_t)priv->wov_wp - priv->wov_rp);
517 else
518 req = min(req, sizeof(priv->wov_buf) - priv->wov_rp);
519
520 memcpy(runtime->dma_area + priv->wov_dma_offset,
521 priv->wov_buf + priv->wov_rp, req);
522
523 priv->wov_dma_offset += req;
524 if (priv->wov_dma_offset == runtime->dma_bytes)
525 priv->wov_dma_offset = 0;
526
527 priv->wov_rp += req;
528 if (priv->wov_rp == sizeof(priv->wov_buf))
529 priv->wov_rp = 0;
530
531 len -= req;
532 }
533
534 snd_pcm_period_elapsed(priv->wov_substream);
535}
536
537static void wov_queue_try_dequeue(struct cros_ec_codec_priv *priv)
538{
539 size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream);
540
541 while (period_bytes && wov_queue_size(priv) >= period_bytes) {
542 wov_queue_dequeue(priv, period_bytes);
543 period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream);
544 }
545}
546
547static void wov_queue_enqueue(struct cros_ec_codec_priv *priv,
548 uint8_t *addr, size_t len, bool iomem)
549{
550 size_t req;
551
552 while (len) {
553 if (wov_queue_full(priv)) {
554 wov_queue_try_dequeue(priv);
555
556 if (wov_queue_full(priv)) {
557 dev_err(priv->dev, "overrun detected\n");
558 return;
559 }
560 }
561
562 if (priv->wov_wp >= priv->wov_rp)
563 req = sizeof(priv->wov_buf) - priv->wov_wp;
564 else
565 /* Note: waste 1-byte to differentiate full and empty */
566 req = priv->wov_rp - priv->wov_wp - 1;
567 req = min(req, len);
568
569 if (iomem)
570 memcpy_fromio(priv->wov_buf + priv->wov_wp,
571 (void __force __iomem *)addr, req);
572 else
573 memcpy(priv->wov_buf + priv->wov_wp, addr, req);
574
575 priv->wov_wp += req;
576 if (priv->wov_wp == sizeof(priv->wov_buf))
577 priv->wov_wp = 0;
578
579 addr += req;
580 len -= req;
581 }
582
583 wov_queue_try_dequeue(priv);
584}
585
586static int wov_read_audio_shm(struct cros_ec_codec_priv *priv)
587{
588 struct ec_param_ec_codec_wov p;
589 struct ec_response_ec_codec_wov_read_audio_shm r;
590 int ret;
591
592 p.cmd = EC_CODEC_WOV_READ_AUDIO_SHM;
593 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
594 (uint8_t *)&p, sizeof(p),
595 (uint8_t *)&r, sizeof(r));
596 if (ret) {
597 dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n");
598 return ret;
599 }
600
601 if (!r.len)
602 dev_dbg(priv->dev, "no data, sleep\n");
603 else
604 wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len,
605 priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM);
606 return -EAGAIN;
607}
608
609static int wov_read_audio(struct cros_ec_codec_priv *priv)
610{
611 struct ec_param_ec_codec_wov p;
612 struct ec_response_ec_codec_wov_read_audio r;
613 int remain = priv->wov_burst_read ? 16000 : 320;
614 int ret;
615
616 while (remain >= 0) {
617 p.cmd = EC_CODEC_WOV_READ_AUDIO;
618 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
619 (uint8_t *)&p, sizeof(p),
620 (uint8_t *)&r, sizeof(r));
621 if (ret) {
622 dev_err(priv->dev,
623 "failed to EC_CODEC_WOV_READ_AUDIO\n");
624 return ret;
625 }
626
627 if (!r.len) {
628 dev_dbg(priv->dev, "no data, sleep\n");
629 priv->wov_burst_read = false;
630 break;
631 }
632
633 wov_queue_enqueue(priv, r.buf, r.len, false);
634 remain -= r.len;
635 }
636
637 return -EAGAIN;
638}
639
640static void wov_copy_work(struct work_struct *w)
641{
642 struct cros_ec_codec_priv *priv =
643 container_of(w, struct cros_ec_codec_priv, wov_copy_work.work);
644 int ret;
645
646 mutex_lock(&priv->wov_dma_lock);
647 if (!priv->wov_substream) {
648 dev_warn(priv->dev, "no pcm substream\n");
649 goto leave;
650 }
651
652 if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM))
653 ret = wov_read_audio_shm(priv);
654 else
655 ret = wov_read_audio(priv);
656
657 if (ret == -EAGAIN)
658 schedule_delayed_work(&priv->wov_copy_work,
659 msecs_to_jiffies(10));
660 else if (ret)
661 dev_err(priv->dev, "failed to read audio data\n");
662leave:
663 mutex_unlock(&priv->wov_dma_lock);
664}
665
666static int wov_enable_get(struct snd_kcontrol *kcontrol,
667 struct snd_ctl_elem_value *ucontrol)
668{
669 struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
670 struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c);
671
672 ucontrol->value.integer.value[0] = priv->wov_enabled;
673 return 0;
674}
675
676static int wov_enable_put(struct snd_kcontrol *kcontrol,
677 struct snd_ctl_elem_value *ucontrol)
678{
679 struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
680 struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c);
681 int enabled = ucontrol->value.integer.value[0];
682 struct ec_param_ec_codec_wov p;
683 int ret;
684
685 if (priv->wov_enabled != enabled) {
686 if (enabled)
687 p.cmd = EC_CODEC_WOV_ENABLE;
688 else
689 p.cmd = EC_CODEC_WOV_DISABLE;
690
691 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
692 (uint8_t *)&p, sizeof(p), NULL, 0);
693 if (ret) {
694 dev_err(priv->dev, "failed to %s wov\n",
695 enabled ? "enable" : "disable");
696 return ret;
697 }
698
699 priv->wov_enabled = enabled;
700 }
701
702 return 0;
703}
704
705static int wov_set_lang_shm(struct cros_ec_codec_priv *priv,
706 uint8_t *buf, size_t size, uint8_t *digest)
707{
708 struct ec_param_ec_codec_wov p;
709 struct ec_param_ec_codec_wov_set_lang_shm *pp = &p.set_lang_shm_param;
710 int ret;
711
712 if (size > priv->wov_lang_shm_len) {
713 dev_err(priv->dev, "no enough SHM size: %d\n",
714 priv->wov_lang_shm_len);
715 return -EIO;
716 }
717
718 switch (priv->wov_lang_shm_type) {
719 case EC_CODEC_SHM_TYPE_EC_RAM:
720 memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p,
721 buf, size);
722 memset_io((void __force __iomem *)priv->wov_lang_shm_p + size,
723 0, priv->wov_lang_shm_len - size);
724 break;
725 case EC_CODEC_SHM_TYPE_SYSTEM_RAM:
726 memcpy(priv->wov_lang_shm_p, buf, size);
727 memset(priv->wov_lang_shm_p + size, 0,
728 priv->wov_lang_shm_len - size);
729
730 /* make sure write to memory before calling host command */
731 wmb();
732 break;
733 }
734
735 p.cmd = EC_CODEC_WOV_SET_LANG_SHM;
736 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE);
737 pp->total_len = size;
738 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
739 (uint8_t *)&p, sizeof(p), NULL, 0);
740 if (ret) {
741 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n");
742 return ret;
743 }
744
745 return 0;
746}
747
748static int wov_set_lang(struct cros_ec_codec_priv *priv,
749 uint8_t *buf, size_t size, uint8_t *digest)
750{
751 struct ec_param_ec_codec_wov p;
752 struct ec_param_ec_codec_wov_set_lang *pp = &p.set_lang_param;
753 size_t i, req;
754 int ret;
755
756 for (i = 0; i < size; i += req) {
757 req = min(size - i, ARRAY_SIZE(pp->buf));
758
759 p.cmd = EC_CODEC_WOV_SET_LANG;
760 memcpy(pp->hash, digest, SHA256_DIGEST_SIZE);
761 pp->total_len = size;
762 pp->offset = i;
763 memcpy(pp->buf, buf + i, req);
764 pp->len = req;
765 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
766 (uint8_t *)&p, sizeof(p), NULL, 0);
767 if (ret) {
768 dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n");
769 return ret;
770 }
771 }
772
773 return 0;
774}
775
776static int wov_hotword_model_put(struct snd_kcontrol *kcontrol,
777 const unsigned int __user *bytes,
778 unsigned int size)
779{
780 struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
781 struct cros_ec_codec_priv *priv =
782 snd_soc_component_get_drvdata(component);
783 struct ec_param_ec_codec_wov p;
784 struct ec_response_ec_codec_wov_get_lang r;
785 uint8_t digest[SHA256_DIGEST_SIZE];
786 uint8_t *buf;
787 int ret;
788
789 /* Skips the TLV header. */
790 bytes += 2;
791 size -= 8;
792
793 dev_dbg(priv->dev, "%s: size=%d\n", __func__, size);
794
795 buf = memdup_user(bytes, size);
796 if (IS_ERR(buf))
797 return PTR_ERR(buf);
798
799 ret = calculate_sha256(priv, buf, size, digest);
800 if (ret)
801 goto leave;
802
803 p.cmd = EC_CODEC_WOV_GET_LANG;
804 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV,
805 (uint8_t *)&p, sizeof(p),
806 (uint8_t *)&r, sizeof(r));
807 if (ret)
808 goto leave;
809
810 if (memcmp(digest, r.hash, SHA256_DIGEST_SIZE) == 0) {
811 dev_dbg(priv->dev, "not updated");
812 goto leave;
813 }
814
815 if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM))
816 ret = wov_set_lang_shm(priv, buf, size, digest);
817 else
818 ret = wov_set_lang(priv, buf, size, digest);
819
820leave:
821 kfree(buf);
822 return ret;
823}
824
825static struct snd_kcontrol_new wov_controls[] = {
826 SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0,
827 wov_enable_get, wov_enable_put),
828 SND_SOC_BYTES_TLV("Hotword Model", 0x11000, NULL,
829 wov_hotword_model_put),
830};
831
832static struct snd_soc_dai_driver wov_dai_driver = {
833 .name = "Wake on Voice",
834 .capture = {
835 .stream_name = "WoV Capture",
836 .channels_min = 1,
837 .channels_max = 1,
838 .rates = SNDRV_PCM_RATE_16000,
839 .formats = SNDRV_PCM_FMTBIT_S16_LE,
840 },
841};
842
843static int wov_host_event(struct notifier_block *nb,
844 unsigned long queued_during_suspend, void *notify)
845{
846 struct cros_ec_codec_priv *priv =
847 container_of(nb, struct cros_ec_codec_priv, wov_notifier);
848 u32 host_event;
849
850 dev_dbg(priv->dev, "%s\n", __func__);
851
852 host_event = cros_ec_get_host_event(priv->ec_device);
853 if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_WOV)) {
854 schedule_delayed_work(&priv->wov_copy_work, 0);
855 return NOTIFY_OK;
856 } else {
857 return NOTIFY_DONE;
858 }
859}
860
861static int wov_probe(struct snd_soc_component *component)
862{
863 struct cros_ec_codec_priv *priv =
864 snd_soc_component_get_drvdata(component);
865 int ret;
866
867 mutex_init(&priv->wov_dma_lock);
868 INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work);
869
870 priv->wov_notifier.notifier_call = wov_host_event;
871 ret = blocking_notifier_chain_register(
872 &priv->ec_device->event_notifier, &priv->wov_notifier);
873 if (ret)
874 return ret;
875
876 if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM)) {
877 priv->wov_lang_shm_p = wov_map_shm(priv,
878 EC_CODEC_SHM_ID_WOV_LANG,
879 &priv->wov_lang_shm_len,
880 &priv->wov_lang_shm_type);
881 if (!priv->wov_lang_shm_p)
882 return -EFAULT;
883 }
884
885 if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) {
886 priv->wov_audio_shm_p = wov_map_shm(priv,
887 EC_CODEC_SHM_ID_WOV_AUDIO,
888 &priv->wov_audio_shm_len,
889 &priv->wov_audio_shm_type);
890 if (!priv->wov_audio_shm_p)
891 return -EFAULT;
892 }
893
894 return dmic_probe(component);
895}
896
897static void wov_remove(struct snd_soc_component *component)
898{
899 struct cros_ec_codec_priv *priv =
900 snd_soc_component_get_drvdata(component);
901
902 blocking_notifier_chain_unregister(
903 &priv->ec_device->event_notifier, &priv->wov_notifier);
904}
905
906static int wov_pcm_open(struct snd_soc_component *component,
907 struct snd_pcm_substream *substream)
908{
909 static const struct snd_pcm_hardware hw_param = {
910 .info = SNDRV_PCM_INFO_MMAP |
911 SNDRV_PCM_INFO_INTERLEAVED |
912 SNDRV_PCM_INFO_MMAP_VALID,
913 .formats = SNDRV_PCM_FMTBIT_S16_LE,
914 .rates = SNDRV_PCM_RATE_16000,
915 .channels_min = 1,
916 .channels_max = 1,
917 .period_bytes_min = PAGE_SIZE,
918 .period_bytes_max = 0x20000 / 8,
919 .periods_min = 8,
920 .periods_max = 8,
921 .buffer_bytes_max = 0x20000,
922 };
923
924 return snd_soc_set_runtime_hwparams(substream, &hw_param);
925}
926
927static int wov_pcm_hw_params(struct snd_soc_component *component,
928 struct snd_pcm_substream *substream,
929 struct snd_pcm_hw_params *hw_params)
930{
931 struct cros_ec_codec_priv *priv =
932 snd_soc_component_get_drvdata(component);
933
934 mutex_lock(&priv->wov_dma_lock);
935 priv->wov_substream = substream;
936 priv->wov_rp = priv->wov_wp = 0;
937 priv->wov_dma_offset = 0;
938 priv->wov_burst_read = true;
939 mutex_unlock(&priv->wov_dma_lock);
940
941 return 0;
942}
943
944static int wov_pcm_hw_free(struct snd_soc_component *component,
945 struct snd_pcm_substream *substream)
946{
947 struct cros_ec_codec_priv *priv =
948 snd_soc_component_get_drvdata(component);
949
950 mutex_lock(&priv->wov_dma_lock);
951 wov_queue_dequeue(priv, wov_queue_size(priv));
952 priv->wov_substream = NULL;
953 mutex_unlock(&priv->wov_dma_lock);
954
955 cancel_delayed_work_sync(&priv->wov_copy_work);
956
957 return 0;
958}
959
960static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component,
961 struct snd_pcm_substream *substream)
962{
963 struct snd_pcm_runtime *runtime = substream->runtime;
964 struct cros_ec_codec_priv *priv =
965 snd_soc_component_get_drvdata(component);
966
967 return bytes_to_frames(runtime, priv->wov_dma_offset);
968}
969
970static int wov_pcm_new(struct snd_soc_component *component,
971 struct snd_soc_pcm_runtime *rtd)
972{
973 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC,
974 NULL, 0, 0);
975 return 0;
976}
977
978static const struct snd_soc_component_driver wov_component_driver = {
979 .probe = wov_probe,
980 .remove = wov_remove,
981 .controls = wov_controls,
982 .num_controls = ARRAY_SIZE(wov_controls),
983 .open = wov_pcm_open,
984 .hw_params = wov_pcm_hw_params,
985 .hw_free = wov_pcm_hw_free,
986 .pointer = wov_pcm_pointer,
987 .pcm_construct = wov_pcm_new,
988};
989
990static int cros_ec_codec_platform_probe(struct platform_device *pdev)
991{
992 struct device *dev = &pdev->dev;
993 struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent);
994 struct cros_ec_codec_priv *priv;
995 struct ec_param_ec_codec p;
996 struct ec_response_ec_codec_get_capabilities r;
997 int ret;
998#ifdef CONFIG_OF
999 struct device_node *node;
1000 struct resource res;
1001 u64 ec_shm_size;
1002 const __be32 *regaddr_p;
1003#endif
1004
1005 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1006 if (!priv)
1007 return -ENOMEM;
1008
1009#ifdef CONFIG_OF
1010 regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL);
1011 if (regaddr_p) {
1012 priv->ec_shm_addr = of_read_number(regaddr_p, 2);
1013 priv->ec_shm_len = ec_shm_size;
1014
1015 dev_dbg(dev, "ec_shm_addr=%#llx len=%#x\n",
1016 priv->ec_shm_addr, priv->ec_shm_len);
1017 }
1018
1019 node = of_parse_phandle(dev->of_node, "memory-region", 0);
1020 if (node) {
1021 ret = of_address_to_resource(node, 0, &res);
1022 if (!ret) {
1023 priv->ap_shm_phys_addr = res.start;
1024 priv->ap_shm_len = resource_size(&res);
1025 priv->ap_shm_addr =
1026 (uint64_t)(uintptr_t)devm_ioremap_wc(
1027 dev, priv->ap_shm_phys_addr,
1028 priv->ap_shm_len);
1029 priv->ap_shm_last_alloc = priv->ap_shm_phys_addr;
1030
1031 dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n",
1032 priv->ap_shm_phys_addr, priv->ap_shm_len);
1033 }
1034 }
1035#endif
1036
1037 priv->dev = dev;
1038 priv->ec_device = ec_device;
1039 atomic_set(&priv->dmic_probed, 0);
1040
1041 p.cmd = EC_CODEC_GET_CAPABILITIES;
1042 ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC,
1043 (uint8_t *)&p, sizeof(p),
1044 (uint8_t *)&r, sizeof(r));
1045 if (ret) {
1046 dev_err(dev, "failed to EC_CODEC_GET_CAPABILITIES\n");
1047 return ret;
1048 }
1049 priv->ec_capabilities = r.capabilities;
1050
1051 platform_set_drvdata(pdev, priv);
1052
1053 ret = devm_snd_soc_register_component(dev, &i2s_rx_component_driver,
1054 &i2s_rx_dai_driver, 1);
1055 if (ret)
1056 return ret;
1057
1058 return devm_snd_soc_register_component(dev, &wov_component_driver,
1059 &wov_dai_driver, 1);
1060}
1061
1062#ifdef CONFIG_OF
1063static const struct of_device_id cros_ec_codec_of_match[] = {
1064 { .compatible = "google,cros-ec-codec" },
1065 {},
1066};
1067MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match);
1068#endif
1069
1070static const struct acpi_device_id cros_ec_codec_acpi_id[] = {
1071 { "GOOG0013", 0 },
1072 { }
1073};
1074MODULE_DEVICE_TABLE(acpi, cros_ec_codec_acpi_id);
1075
1076static struct platform_driver cros_ec_codec_platform_driver = {
1077 .driver = {
1078 .name = "cros-ec-codec",
1079 .of_match_table = of_match_ptr(cros_ec_codec_of_match),
1080 .acpi_match_table = ACPI_PTR(cros_ec_codec_acpi_id),
1081 },
1082 .probe = cros_ec_codec_platform_probe,
1083};
1084
1085module_platform_driver(cros_ec_codec_platform_driver);
1086
1087MODULE_LICENSE("GPL v2");
1088MODULE_DESCRIPTION("ChromeOS EC codec driver");
1089MODULE_AUTHOR("Cheng-Yi Chiang <cychiang@chromium.org>");
1090MODULE_ALIAS("platform:cros-ec-codec");