diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sh/Kconfig | 5 | ||||
-rw-r--r-- | sound/soc/sh/rcar/Makefile | 5 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsrc-card.c | 489 |
3 files changed, 498 insertions, 1 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 80245b6eebd6..2b3030415573 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -41,6 +41,11 @@ config SND_SOC_RCAR | |||
41 | help | 41 | help |
42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support | 42 | This option enables R-Car SUR/SCU/SSIU/SSI sound support |
43 | 43 | ||
44 | config SND_SOC_RSRC_CARD | ||
45 | tristate "Renesas Sampling Rate Convert Sound Card" | ||
46 | help | ||
47 | This option enables simple sound if you need sampling rate convert | ||
48 | |||
44 | ## | 49 | ## |
45 | ## Boards | 50 | ## Boards |
46 | ## | 51 | ## |
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7b204925b8c5..f1b445173fba 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile | |||
@@ -1,2 +1,5 @@ | |||
1 | snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o | 1 | snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o |
2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file | 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o |
3 | |||
4 | snd-soc-rsrc-card-objs := rsrc-card.o | ||
5 | obj-$(CONFIG_SND_SOC_RSRC_CARD) += snd-soc-rsrc-card.o | ||
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c new file mode 100644 index 000000000000..3baeab726bc3 --- /dev/null +++ b/sound/soc/sh/rcar/rsrc-card.c | |||
@@ -0,0 +1,489 @@ | |||
1 | /* | ||
2 | * Renesas Sampling Rate Convert Sound Card for DPCM | ||
3 | * | ||
4 | * Copyright (C) 2015 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * based on ${LINUX}/sound/soc/generic/simple-card.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <sound/jack.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-dai.h> | ||
23 | |||
24 | struct rsrc_card_of_data { | ||
25 | const char *prefix; | ||
26 | const struct snd_soc_dapm_route *routes; | ||
27 | int num_routes; | ||
28 | }; | ||
29 | |||
30 | static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = { | ||
31 | {"ak4642 Playback", NULL, "DAI0 Playback"}, | ||
32 | {"DAI0 Capture", NULL, "ak4642 Capture"}, | ||
33 | }; | ||
34 | |||
35 | static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = { | ||
36 | .prefix = "ak4642", | ||
37 | .routes = routes_ssi0_ak4642, | ||
38 | .num_routes = ARRAY_SIZE(routes_ssi0_ak4642), | ||
39 | }; | ||
40 | |||
41 | static const struct of_device_id rsrc_card_of_match[] = { | ||
42 | { .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 }, | ||
43 | { .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 }, | ||
44 | {}, | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(of, rsrc_card_of_match); | ||
47 | |||
48 | struct rsrc_card_dai { | ||
49 | const char *name; | ||
50 | unsigned int fmt; | ||
51 | unsigned int sysclk; | ||
52 | struct clk *clk; | ||
53 | }; | ||
54 | |||
55 | #define RSRC_FB_NUM 2 /* FE/BE */ | ||
56 | #define IDX_CPU 0 | ||
57 | #define IDX_CODEC 1 | ||
58 | struct rsrc_card_priv { | ||
59 | struct snd_soc_card snd_card; | ||
60 | struct rsrc_card_dai_props { | ||
61 | struct rsrc_card_dai cpu_dai; | ||
62 | struct rsrc_card_dai codec_dai; | ||
63 | } dai_props[RSRC_FB_NUM]; | ||
64 | struct snd_soc_codec_conf codec_conf; | ||
65 | struct snd_soc_dai_link dai_link[RSRC_FB_NUM]; | ||
66 | }; | ||
67 | |||
68 | #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) | ||
69 | #define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) | ||
70 | #define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i) | ||
71 | #define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) | ||
72 | |||
73 | static int rsrc_card_startup(struct snd_pcm_substream *substream) | ||
74 | { | ||
75 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
76 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
77 | struct rsrc_card_dai_props *dai_props = | ||
78 | &priv->dai_props[rtd - rtd->card->rtd]; | ||
79 | int ret; | ||
80 | |||
81 | ret = clk_prepare_enable(dai_props->cpu_dai.clk); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | ret = clk_prepare_enable(dai_props->codec_dai.clk); | ||
86 | if (ret) | ||
87 | clk_disable_unprepare(dai_props->cpu_dai.clk); | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static void rsrc_card_shutdown(struct snd_pcm_substream *substream) | ||
93 | { | ||
94 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
95 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
96 | struct rsrc_card_dai_props *dai_props = | ||
97 | &priv->dai_props[rtd - rtd->card->rtd]; | ||
98 | |||
99 | clk_disable_unprepare(dai_props->cpu_dai.clk); | ||
100 | |||
101 | clk_disable_unprepare(dai_props->codec_dai.clk); | ||
102 | } | ||
103 | |||
104 | static struct snd_soc_ops rsrc_card_ops = { | ||
105 | .startup = rsrc_card_startup, | ||
106 | .shutdown = rsrc_card_shutdown, | ||
107 | }; | ||
108 | |||
109 | static int __rsrc_card_dai_init(struct snd_soc_dai *dai, | ||
110 | struct rsrc_card_dai *set) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | if (set->fmt) { | ||
115 | ret = snd_soc_dai_set_fmt(dai, set->fmt); | ||
116 | if (ret && ret != -ENOTSUPP) { | ||
117 | dev_err(dai->dev, "set_fmt error\n"); | ||
118 | goto err; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | if (set->sysclk) { | ||
123 | ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); | ||
124 | if (ret && ret != -ENOTSUPP) { | ||
125 | dev_err(dai->dev, "set_sysclk error\n"); | ||
126 | goto err; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | ret = 0; | ||
131 | |||
132 | err: | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
137 | { | ||
138 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
139 | struct snd_soc_dai *codec = rtd->codec_dai; | ||
140 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
141 | struct rsrc_card_dai_props *dai_props; | ||
142 | int num, ret; | ||
143 | |||
144 | num = rtd - rtd->card->rtd; | ||
145 | dai_props = &priv->dai_props[num]; | ||
146 | ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai); | ||
151 | if (ret < 0) | ||
152 | return ret; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int | ||
158 | rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, | ||
159 | struct device_node *np, | ||
160 | struct rsrc_card_dai *dai, | ||
161 | struct snd_soc_dai_link *dai_link, | ||
162 | int *args_count) | ||
163 | { | ||
164 | struct device *dev = rsrc_priv_to_dev(priv); | ||
165 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); | ||
166 | struct of_phandle_args args; | ||
167 | struct device_node **p_node; | ||
168 | struct clk *clk; | ||
169 | const char **dai_name; | ||
170 | const char **name; | ||
171 | u32 val; | ||
172 | int ret; | ||
173 | |||
174 | if (args_count) { | ||
175 | p_node = &dai_link->cpu_of_node; | ||
176 | dai_name = &dai_link->cpu_dai_name; | ||
177 | name = &dai_link->cpu_name; | ||
178 | } else { | ||
179 | p_node = &dai_link->codec_of_node; | ||
180 | dai_name = &dai_link->codec_dai_name; | ||
181 | name = &dai_link->codec_name; | ||
182 | } | ||
183 | |||
184 | if (!np) { | ||
185 | /* use snd-soc-dummy */ | ||
186 | *p_node = NULL; | ||
187 | *dai_name = "snd-soc-dummy-dai"; | ||
188 | *name = "snd-soc-dummy"; | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * Get node via "sound-dai = <&phandle port>" | ||
194 | * it will be used as xxx_of_node on soc_bind_dai_link() | ||
195 | */ | ||
196 | ret = of_parse_phandle_with_args(np, "sound-dai", | ||
197 | "#sound-dai-cells", 0, &args); | ||
198 | if (ret) | ||
199 | return ret; | ||
200 | |||
201 | *p_node = args.np; | ||
202 | |||
203 | /* Get dai->name */ | ||
204 | ret = snd_soc_of_get_dai_name(np, dai_name); | ||
205 | if (ret < 0) | ||
206 | return ret; | ||
207 | |||
208 | /* | ||
209 | * FIXME | ||
210 | * | ||
211 | * rsrc assumes DPCM playback/capture | ||
212 | */ | ||
213 | dai_link->dpcm_playback = 1; | ||
214 | dai_link->dpcm_capture = 1; | ||
215 | |||
216 | if (args_count) { | ||
217 | *args_count = args.args_count; | ||
218 | dai_link->dynamic = 1; | ||
219 | } else { | ||
220 | dai_link->no_pcm = 1; | ||
221 | priv->codec_conf.of_node = (*p_node); | ||
222 | priv->codec_conf.name_prefix = of_data->prefix; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Parse dai->sysclk come from "clocks = <&xxx>" | ||
227 | * (if system has common clock) | ||
228 | * or "system-clock-frequency = <xxx>" | ||
229 | * or device's module clock. | ||
230 | */ | ||
231 | if (of_property_read_bool(np, "clocks")) { | ||
232 | clk = of_clk_get(np, 0); | ||
233 | if (IS_ERR(clk)) { | ||
234 | ret = PTR_ERR(clk); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | dai->sysclk = clk_get_rate(clk); | ||
239 | dai->clk = clk; | ||
240 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { | ||
241 | dai->sysclk = val; | ||
242 | } else { | ||
243 | clk = of_clk_get(args.np, 0); | ||
244 | if (!IS_ERR(clk)) | ||
245 | dai->sysclk = clk_get_rate(clk); | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int rsrc_card_parse_daifmt(struct device_node *node, | ||
252 | struct rsrc_card_priv *priv, | ||
253 | struct device_node *codec, | ||
254 | int idx) | ||
255 | { | ||
256 | struct device_node *bitclkmaster = NULL; | ||
257 | struct device_node *framemaster = NULL; | ||
258 | struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); | ||
259 | struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai; | ||
260 | struct rsrc_card_dai *codec_dai = &dai_props->codec_dai; | ||
261 | unsigned int daifmt; | ||
262 | |||
263 | daifmt = snd_soc_of_parse_daifmt(node, NULL, | ||
264 | &bitclkmaster, &framemaster); | ||
265 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
266 | |||
267 | if (!bitclkmaster && !framemaster) | ||
268 | return -EINVAL; | ||
269 | |||
270 | if (codec == bitclkmaster) | ||
271 | daifmt |= (codec == framemaster) ? | ||
272 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
273 | else | ||
274 | daifmt |= (codec == framemaster) ? | ||
275 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
276 | |||
277 | cpu_dai->fmt = daifmt; | ||
278 | codec_dai->fmt = daifmt; | ||
279 | |||
280 | of_node_put(bitclkmaster); | ||
281 | of_node_put(framemaster); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int rsrc_card_dai_link_of(struct device_node *node, | ||
287 | struct rsrc_card_priv *priv, | ||
288 | int idx) | ||
289 | { | ||
290 | struct device *dev = rsrc_priv_to_dev(priv); | ||
291 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | ||
292 | struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); | ||
293 | struct device_node *cpu = NULL; | ||
294 | struct device_node *codec = NULL; | ||
295 | char *name; | ||
296 | char prop[128]; | ||
297 | int ret, cpu_args; | ||
298 | |||
299 | cpu = of_get_child_by_name(node, "cpu"); | ||
300 | codec = of_get_child_by_name(node, "codec"); | ||
301 | |||
302 | if (!cpu || !codec) { | ||
303 | ret = -EINVAL; | ||
304 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | ||
305 | goto dai_link_of_err; | ||
306 | } | ||
307 | |||
308 | ret = rsrc_card_parse_daifmt(node, priv, codec, idx); | ||
309 | if (ret < 0) | ||
310 | goto dai_link_of_err; | ||
311 | |||
312 | ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL, | ||
313 | &dai_props->cpu_dai, | ||
314 | dai_link, | ||
315 | &cpu_args); | ||
316 | if (ret < 0) | ||
317 | goto dai_link_of_err; | ||
318 | |||
319 | ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL, | ||
320 | &dai_props->codec_dai, | ||
321 | dai_link, | ||
322 | NULL); | ||
323 | if (ret < 0) | ||
324 | goto dai_link_of_err; | ||
325 | |||
326 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | ||
327 | ret = -EINVAL; | ||
328 | goto dai_link_of_err; | ||
329 | } | ||
330 | |||
331 | /* Simple Card assumes platform == cpu */ | ||
332 | dai_link->platform_of_node = dai_link->cpu_of_node; | ||
333 | |||
334 | /* DAI link name is created from CPU/CODEC dai name */ | ||
335 | name = devm_kzalloc(dev, | ||
336 | strlen(dai_link->cpu_dai_name) + | ||
337 | strlen(dai_link->codec_dai_name) + 2, | ||
338 | GFP_KERNEL); | ||
339 | if (!name) { | ||
340 | ret = -ENOMEM; | ||
341 | goto dai_link_of_err; | ||
342 | } | ||
343 | |||
344 | sprintf(name, "%s-%s", dai_link->cpu_dai_name, | ||
345 | dai_link->codec_dai_name); | ||
346 | dai_link->name = dai_link->stream_name = name; | ||
347 | dai_link->ops = &rsrc_card_ops; | ||
348 | dai_link->init = rsrc_card_dai_init; | ||
349 | |||
350 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); | ||
351 | dev_dbg(dev, "\tcpu : %s / %04x / %d\n", | ||
352 | dai_link->cpu_dai_name, | ||
353 | dai_props->cpu_dai.fmt, | ||
354 | dai_props->cpu_dai.sysclk); | ||
355 | dev_dbg(dev, "\tcodec : %s / %04x / %d\n", | ||
356 | dai_link->codec_dai_name, | ||
357 | dai_props->codec_dai.fmt, | ||
358 | dai_props->codec_dai.sysclk); | ||
359 | |||
360 | /* | ||
361 | * In soc_bind_dai_link() will check cpu name after | ||
362 | * of_node matching if dai_link has cpu_dai_name. | ||
363 | * but, it will never match if name was created by | ||
364 | * fmt_single_name() remove cpu_dai_name if cpu_args | ||
365 | * was 0. See: | ||
366 | * fmt_single_name() | ||
367 | * fmt_multiple_name() | ||
368 | */ | ||
369 | if (!cpu_args) | ||
370 | dai_link->cpu_dai_name = NULL; | ||
371 | |||
372 | dai_link_of_err: | ||
373 | of_node_put(cpu); | ||
374 | of_node_put(codec); | ||
375 | |||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int rsrc_card_parse_of(struct device_node *node, | ||
380 | struct rsrc_card_priv *priv) | ||
381 | { | ||
382 | struct device *dev = rsrc_priv_to_dev(priv); | ||
383 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); | ||
384 | int ret; | ||
385 | int i; | ||
386 | |||
387 | if (!node) | ||
388 | return -EINVAL; | ||
389 | |||
390 | /* Parse the card name from DT */ | ||
391 | snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); | ||
392 | |||
393 | /* DAPM routes */ | ||
394 | priv->snd_card.of_dapm_routes = of_data->routes; | ||
395 | priv->snd_card.num_of_dapm_routes = of_data->num_routes; | ||
396 | |||
397 | dev_dbg(dev, "New rsrc-audio-card: %s\n", priv->snd_card.name ? | ||
398 | priv->snd_card.name : ""); | ||
399 | |||
400 | /* FE/BE */ | ||
401 | for (i = 0; i < RSRC_FB_NUM; i++) { | ||
402 | ret = rsrc_card_dai_link_of(node, priv, i); | ||
403 | if (ret < 0) | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | if (!priv->snd_card.name) | ||
408 | priv->snd_card.name = priv->snd_card.dai_link->name; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | /* Decrease the reference count of the device nodes */ | ||
414 | static int rsrc_card_unref(struct snd_soc_card *card) | ||
415 | { | ||
416 | struct snd_soc_dai_link *dai_link; | ||
417 | int num_links; | ||
418 | |||
419 | for (num_links = 0, dai_link = card->dai_link; | ||
420 | num_links < card->num_links; | ||
421 | num_links++, dai_link++) { | ||
422 | of_node_put(dai_link->cpu_of_node); | ||
423 | of_node_put(dai_link->codec_of_node); | ||
424 | } | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int rsrc_card_probe(struct platform_device *pdev) | ||
429 | { | ||
430 | struct rsrc_card_priv *priv; | ||
431 | struct snd_soc_dai_link *dai_link; | ||
432 | struct device_node *np = pdev->dev.of_node; | ||
433 | struct device *dev = &pdev->dev; | ||
434 | int ret; | ||
435 | |||
436 | /* Allocate the private data */ | ||
437 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
438 | if (!priv) | ||
439 | return -ENOMEM; | ||
440 | |||
441 | /* Init snd_soc_card */ | ||
442 | priv->snd_card.owner = THIS_MODULE; | ||
443 | priv->snd_card.dev = dev; | ||
444 | dai_link = priv->dai_link; | ||
445 | priv->snd_card.dai_link = dai_link; | ||
446 | priv->snd_card.num_links = RSRC_FB_NUM; | ||
447 | priv->snd_card.codec_conf = &priv->codec_conf; | ||
448 | priv->snd_card.num_configs = 1; | ||
449 | |||
450 | ret = rsrc_card_parse_of(np, priv); | ||
451 | if (ret < 0) { | ||
452 | if (ret != -EPROBE_DEFER) | ||
453 | dev_err(dev, "parse error %d\n", ret); | ||
454 | goto err; | ||
455 | } | ||
456 | |||
457 | snd_soc_card_set_drvdata(&priv->snd_card, priv); | ||
458 | |||
459 | ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); | ||
460 | if (ret >= 0) | ||
461 | return ret; | ||
462 | err: | ||
463 | rsrc_card_unref(&priv->snd_card); | ||
464 | |||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | static int rsrc_card_remove(struct platform_device *pdev) | ||
469 | { | ||
470 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
471 | |||
472 | return rsrc_card_unref(card); | ||
473 | } | ||
474 | |||
475 | static struct platform_driver rsrc_card = { | ||
476 | .driver = { | ||
477 | .name = "renesas-src-audio-card", | ||
478 | .of_match_table = rsrc_card_of_match, | ||
479 | }, | ||
480 | .probe = rsrc_card_probe, | ||
481 | .remove = rsrc_card_remove, | ||
482 | }; | ||
483 | |||
484 | module_platform_driver(rsrc_card); | ||
485 | |||
486 | MODULE_ALIAS("platform:renesas-src-audio-card"); | ||
487 | MODULE_LICENSE("GPL"); | ||
488 | MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card"); | ||
489 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | ||