Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | // SPDX-License-Identifier: GPL-2.0 // // audio-graph-card2-custom-sample.c // // Copyright (C) 2020 Renesas Electronics Corp. // Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> // #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <sound/graph_card.h> /* * Custom driver can have own priv * which includes simple_util_priv. */ struct custom_priv { struct simple_util_priv simple_priv; /* custom driver's own params */ int custom_params; }; /* You can get custom_priv from simple_priv */ #define simple_to_custom(simple) container_of((simple), struct custom_priv, simple_priv) static int custom_card_probe(struct snd_soc_card *card) { struct simple_util_priv *simple_priv = snd_soc_card_get_drvdata(card); struct custom_priv *custom_priv = simple_to_custom(simple_priv); struct device *dev = simple_priv_to_dev(simple_priv); dev_info(dev, "custom probe\n"); custom_priv->custom_params = 1; /* you can use generic probe function */ return graph_util_card_probe(card); } static int custom_hook_pre(struct simple_util_priv *priv) { struct device *dev = simple_priv_to_dev(priv); /* You can custom before parsing */ dev_info(dev, "hook : %s\n", __func__); return 0; } static int custom_hook_post(struct simple_util_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_card *card; /* You can custom after parsing */ dev_info(dev, "hook : %s\n", __func__); /* overwrite .probe sample */ card = simple_priv_to_card(priv); card->probe = custom_card_probe; return 0; } static int custom_normal(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); /* * You can custom Normal parsing * before/affter audio_graph2_link_normal() */ dev_info(dev, "hook : %s\n", __func__); return audio_graph2_link_normal(priv, lnk, li); } static int custom_dpcm(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); /* * You can custom DPCM parsing * before/affter audio_graph2_link_dpcm() */ dev_info(dev, "hook : %s\n", __func__); return audio_graph2_link_dpcm(priv, lnk, li); } static int custom_c2c(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); /* * You can custom Codec2Codec parsing * before/affter audio_graph2_link_c2c() */ dev_info(dev, "hook : %s\n", __func__); return audio_graph2_link_c2c(priv, lnk, li); } /* * audio-graph-card2 has many hooks for your customizing. */ static struct graph2_custom_hooks custom_hooks = { .hook_pre = custom_hook_pre, .hook_post = custom_hook_post, .custom_normal = custom_normal, .custom_dpcm = custom_dpcm, .custom_c2c = custom_c2c, }; static int custom_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct device *dev = simple_priv_to_dev(priv); dev_info(dev, "custom startup\n"); return simple_util_startup(substream); } /* You can use custom ops */ static const struct snd_soc_ops custom_ops = { .startup = custom_startup, .shutdown = simple_util_shutdown, .hw_params = simple_util_hw_params, }; static int custom_probe(struct platform_device *pdev) { struct custom_priv *custom_priv; struct simple_util_priv *simple_priv; struct device *dev = &pdev->dev; int ret; custom_priv = devm_kzalloc(dev, sizeof(*custom_priv), GFP_KERNEL); if (!custom_priv) return -ENOMEM; simple_priv = &custom_priv->simple_priv; simple_priv->ops = &custom_ops; /* customize dai_link ops */ /* "audio-graph-card2-custom-sample" is too long */ simple_priv->snd_card.name = "card2-custom"; /* use audio-graph-card2 parsing with own custom hooks */ ret = audio_graph2_parse_of(simple_priv, dev, &custom_hooks); if (ret < 0) return ret; /* customize more if needed */ return 0; } static const struct of_device_id custom_of_match[] = { { .compatible = "audio-graph-card2-custom-sample", }, {}, }; MODULE_DEVICE_TABLE(of, custom_of_match); static struct platform_driver custom_card = { .driver = { .name = "audio-graph-card2-custom-sample", .of_match_table = custom_of_match, }, .probe = custom_probe, .remove_new = simple_util_remove, }; module_platform_driver(custom_card); MODULE_ALIAS("platform:asoc-audio-graph-card2-custom-sample"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ASoC Audio Graph Card2 Custom Sample"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); |