Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
| 2 | // |
| 3 | // Copyright (c) 2018 BayLibre, SAS. |
| 4 | // Author: Jerome Brunet <jbrunet@baylibre.com> |
| 5 | |
| 6 | #include <linux/module.h> |
| 7 | #include <linux/of_platform.h> |
| 8 | #include <sound/soc.h> |
| 9 | #include <sound/soc-dai.h> |
| 10 | |
| 11 | #include "axg-tdm.h" |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 12 | #include "meson-card.h" |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 13 | |
| 14 | struct axg_dai_link_tdm_mask { |
| 15 | u32 tx; |
| 16 | u32 rx; |
| 17 | }; |
| 18 | |
| 19 | struct axg_dai_link_tdm_data { |
| 20 | unsigned int mclk_fs; |
| 21 | unsigned int slots; |
| 22 | unsigned int slot_width; |
| 23 | u32 *tx_mask; |
| 24 | u32 *rx_mask; |
| 25 | struct axg_dai_link_tdm_mask *codec_masks; |
| 26 | }; |
| 27 | |
Jerome Brunet | 0a8f111 | 2019-05-15 15:18:57 +0200 | [diff] [blame] | 28 | /* |
| 29 | * Base params for the codec to codec links |
| 30 | * Those will be over-written by the CPU side of the link |
| 31 | */ |
| 32 | static const struct snd_soc_pcm_stream codec_params = { |
| 33 | .formats = SNDRV_PCM_FMTBIT_S24_LE, |
| 34 | .rate_min = 5525, |
| 35 | .rate_max = 192000, |
| 36 | .channels_min = 1, |
| 37 | .channels_max = 8, |
| 38 | }; |
| 39 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 40 | static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, |
| 41 | struct snd_pcm_hw_params *params) |
| 42 | { |
Kuninori Morimoto | 371a014 | 2020-07-20 10:19:14 +0900 | [diff] [blame] | 43 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 44 | struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 45 | struct axg_dai_link_tdm_data *be = |
| 46 | (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 47 | |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 48 | return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | static const struct snd_soc_ops axg_card_tdm_be_ops = { |
| 52 | .hw_params = axg_card_tdm_be_hw_params, |
| 53 | }; |
| 54 | |
| 55 | static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) |
| 56 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 57 | struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 58 | struct axg_dai_link_tdm_data *be = |
| 59 | (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; |
| 60 | struct snd_soc_dai *codec_dai; |
| 61 | int ret, i; |
| 62 | |
Kuninori Morimoto | b5c52f5 | 2020-03-09 13:07:48 +0900 | [diff] [blame] | 63 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 64 | ret = snd_soc_dai_set_tdm_slot(codec_dai, |
| 65 | be->codec_masks[i].tx, |
| 66 | be->codec_masks[i].rx, |
| 67 | be->slots, be->slot_width); |
| 68 | if (ret && ret != -ENOTSUPP) { |
| 69 | dev_err(codec_dai->dev, |
| 70 | "setting tdm link slots failed\n"); |
| 71 | return ret; |
| 72 | } |
| 73 | } |
| 74 | |
Kuninori Morimoto | 385a5c6 | 2020-03-23 14:19:32 +0900 | [diff] [blame] | 75 | ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), be->tx_mask, be->rx_mask, |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 76 | be->slots, be->slot_width); |
| 77 | if (ret) { |
Kuninori Morimoto | 385a5c6 | 2020-03-23 14:19:32 +0900 | [diff] [blame] | 78 | dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 79 | return ret; |
| 80 | } |
| 81 | |
| 82 | return 0; |
| 83 | } |
| 84 | |
| 85 | static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd) |
| 86 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 87 | struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 88 | struct axg_dai_link_tdm_data *be = |
| 89 | (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; |
| 90 | int ret; |
| 91 | |
| 92 | /* The loopback rx_mask is the pad tx_mask */ |
Kuninori Morimoto | 385a5c6 | 2020-03-23 14:19:32 +0900 | [diff] [blame] | 93 | ret = axg_tdm_set_tdm_slots(asoc_rtd_to_cpu(rtd, 0), NULL, be->tx_mask, |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 94 | be->slots, be->slot_width); |
| 95 | if (ret) { |
Kuninori Morimoto | 385a5c6 | 2020-03-23 14:19:32 +0900 | [diff] [blame] | 96 | dev_err(asoc_rtd_to_cpu(rtd, 0)->dev, "setting tdm link slots failed\n"); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 97 | return ret; |
| 98 | } |
| 99 | |
| 100 | return 0; |
| 101 | } |
| 102 | |
| 103 | static int axg_card_add_tdm_loopback(struct snd_soc_card *card, |
| 104 | int *index) |
| 105 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 106 | struct meson_card *priv = snd_soc_card_get_drvdata(card); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 107 | struct snd_soc_dai_link *pad = &card->dai_link[*index]; |
| 108 | struct snd_soc_dai_link *lb; |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 109 | struct snd_soc_dai_link_component *dlc; |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 110 | int ret; |
| 111 | |
| 112 | /* extend links */ |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 113 | ret = meson_card_reallocate_links(card, card->num_links + 1); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 114 | if (ret) |
| 115 | return ret; |
| 116 | |
| 117 | lb = &card->dai_link[*index + 1]; |
| 118 | |
Jing Xiangfeng | bd054ec | 2020-07-17 16:22:42 +0800 | [diff] [blame] | 119 | lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 120 | if (!lb->name) |
| 121 | return -ENOMEM; |
| 122 | |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 123 | dlc = devm_kzalloc(card->dev, 2 * sizeof(*dlc), GFP_KERNEL); |
| 124 | if (!dlc) |
| 125 | return -ENOMEM; |
| 126 | |
| 127 | lb->cpus = &dlc[0]; |
| 128 | lb->codecs = &dlc[1]; |
| 129 | lb->num_cpus = 1; |
| 130 | lb->num_codecs = 1; |
| 131 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 132 | lb->stream_name = lb->name; |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 133 | lb->cpus->of_node = pad->cpus->of_node; |
| 134 | lb->cpus->dai_name = "TDM Loopback"; |
| 135 | lb->codecs->name = "snd-soc-dummy"; |
| 136 | lb->codecs->dai_name = "snd-soc-dummy-dai"; |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 137 | lb->dpcm_capture = 1; |
| 138 | lb->no_pcm = 1; |
| 139 | lb->ops = &axg_card_tdm_be_ops; |
| 140 | lb->init = axg_card_tdm_dai_lb_init; |
| 141 | |
| 142 | /* Provide the same link data to the loopback */ |
| 143 | priv->link_data[*index + 1] = priv->link_data[*index]; |
| 144 | |
| 145 | /* |
| 146 | * axg_card_clean_references() will iterate over this link, |
| 147 | * make sure the node count is balanced |
| 148 | */ |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 149 | of_node_get(lb->cpus->of_node); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 150 | |
| 151 | /* Let add_links continue where it should */ |
| 152 | *index += 1; |
| 153 | |
| 154 | return 0; |
| 155 | } |
| 156 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 157 | static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card, |
| 158 | struct snd_soc_dai_link *link, |
| 159 | struct device_node *node, |
| 160 | struct axg_dai_link_tdm_data *be) |
| 161 | { |
| 162 | char propname[32]; |
| 163 | u32 tx, rx; |
| 164 | int i; |
| 165 | |
| 166 | be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, |
| 167 | sizeof(*be->tx_mask), GFP_KERNEL); |
| 168 | be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES, |
| 169 | sizeof(*be->rx_mask), GFP_KERNEL); |
| 170 | if (!be->tx_mask || !be->rx_mask) |
| 171 | return -ENOMEM; |
| 172 | |
| 173 | for (i = 0, tx = 0; i < AXG_TDM_NUM_LANES; i++) { |
| 174 | snprintf(propname, 32, "dai-tdm-slot-tx-mask-%d", i); |
| 175 | snd_soc_of_get_slot_mask(node, propname, &be->tx_mask[i]); |
| 176 | tx = max(tx, be->tx_mask[i]); |
| 177 | } |
| 178 | |
| 179 | /* Disable playback is the interface has no tx slots */ |
| 180 | if (!tx) |
| 181 | link->dpcm_playback = 0; |
| 182 | |
| 183 | for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) { |
| 184 | snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i); |
| 185 | snd_soc_of_get_slot_mask(node, propname, &be->rx_mask[i]); |
| 186 | rx = max(rx, be->rx_mask[i]); |
| 187 | } |
| 188 | |
| 189 | /* Disable capture is the interface has no rx slots */ |
| 190 | if (!rx) |
| 191 | link->dpcm_capture = 0; |
| 192 | |
| 193 | /* ... but the interface should at least have one of them */ |
| 194 | if (!tx && !rx) { |
| 195 | dev_err(card->dev, "tdm link has no cpu slots\n"); |
| 196 | return -EINVAL; |
| 197 | } |
| 198 | |
| 199 | of_property_read_u32(node, "dai-tdm-slot-num", &be->slots); |
| 200 | if (!be->slots) { |
| 201 | /* |
| 202 | * If the slot number is not provided, set it such as it |
| 203 | * accommodates the largest mask |
| 204 | */ |
| 205 | be->slots = fls(max(tx, rx)); |
| 206 | } else if (be->slots < fls(max(tx, rx)) || be->slots > 32) { |
| 207 | /* |
| 208 | * Error if the slots can't accommodate the largest mask or |
| 209 | * if it is just too big |
| 210 | */ |
| 211 | dev_err(card->dev, "bad slot number\n"); |
| 212 | return -EINVAL; |
| 213 | } |
| 214 | |
| 215 | of_property_read_u32(node, "dai-tdm-slot-width", &be->slot_width); |
| 216 | |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | static int axg_card_parse_codecs_masks(struct snd_soc_card *card, |
| 221 | struct snd_soc_dai_link *link, |
| 222 | struct device_node *node, |
| 223 | struct axg_dai_link_tdm_data *be) |
| 224 | { |
| 225 | struct axg_dai_link_tdm_mask *codec_mask; |
| 226 | struct device_node *np; |
| 227 | |
| 228 | codec_mask = devm_kcalloc(card->dev, link->num_codecs, |
| 229 | sizeof(*codec_mask), GFP_KERNEL); |
| 230 | if (!codec_mask) |
| 231 | return -ENOMEM; |
| 232 | |
| 233 | be->codec_masks = codec_mask; |
| 234 | |
| 235 | for_each_child_of_node(node, np) { |
| 236 | snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", |
| 237 | &codec_mask->rx); |
| 238 | snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask", |
| 239 | &codec_mask->tx); |
| 240 | |
| 241 | codec_mask++; |
| 242 | } |
| 243 | |
| 244 | return 0; |
| 245 | } |
| 246 | |
| 247 | static int axg_card_parse_tdm(struct snd_soc_card *card, |
| 248 | struct device_node *node, |
| 249 | int *index) |
| 250 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 251 | struct meson_card *priv = snd_soc_card_get_drvdata(card); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 252 | struct snd_soc_dai_link *link = &card->dai_link[*index]; |
| 253 | struct axg_dai_link_tdm_data *be; |
| 254 | int ret; |
| 255 | |
| 256 | /* Allocate tdm link parameters */ |
| 257 | be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL); |
| 258 | if (!be) |
| 259 | return -ENOMEM; |
| 260 | priv->link_data[*index] = be; |
| 261 | |
| 262 | /* Setup tdm link */ |
| 263 | link->ops = &axg_card_tdm_be_ops; |
| 264 | link->init = axg_card_tdm_dai_init; |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 265 | link->dai_fmt = meson_card_parse_daifmt(node, link->cpus->of_node); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 266 | |
| 267 | of_property_read_u32(node, "mclk-fs", &be->mclk_fs); |
| 268 | |
| 269 | ret = axg_card_parse_cpu_tdm_slots(card, link, node, be); |
| 270 | if (ret) { |
| 271 | dev_err(card->dev, "error parsing tdm link slots\n"); |
| 272 | return ret; |
| 273 | } |
| 274 | |
| 275 | ret = axg_card_parse_codecs_masks(card, link, node, be); |
| 276 | if (ret) |
| 277 | return ret; |
| 278 | |
| 279 | /* Add loopback if the pad dai has playback */ |
| 280 | if (link->dpcm_playback) { |
| 281 | ret = axg_card_add_tdm_loopback(card, index); |
| 282 | if (ret) |
| 283 | return ret; |
| 284 | } |
| 285 | |
| 286 | return 0; |
| 287 | } |
| 288 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 289 | static int axg_card_cpu_is_capture_fe(struct device_node *np) |
| 290 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 291 | return of_device_is_compatible(np, DT_PREFIX "axg-toddr"); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | static int axg_card_cpu_is_playback_fe(struct device_node *np) |
| 295 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 296 | return of_device_is_compatible(np, DT_PREFIX "axg-frddr"); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 297 | } |
| 298 | |
| 299 | static int axg_card_cpu_is_tdm_iface(struct device_node *np) |
| 300 | { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 301 | return of_device_is_compatible(np, DT_PREFIX "axg-tdm-iface"); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 302 | } |
| 303 | |
Jerome Brunet | 0a8f111 | 2019-05-15 15:18:57 +0200 | [diff] [blame] | 304 | static int axg_card_cpu_is_codec(struct device_node *np) |
| 305 | { |
Jerome Brunet | b38c4a8 | 2020-02-21 16:36:07 +0100 | [diff] [blame] | 306 | return of_device_is_compatible(np, DT_PREFIX "g12a-tohdmitx") || |
| 307 | of_device_is_compatible(np, DT_PREFIX "g12a-toacodec"); |
Jerome Brunet | 0a8f111 | 2019-05-15 15:18:57 +0200 | [diff] [blame] | 308 | } |
| 309 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 310 | static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, |
| 311 | int *index) |
| 312 | { |
| 313 | struct snd_soc_dai_link *dai_link = &card->dai_link[*index]; |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 314 | struct snd_soc_dai_link_component *cpu; |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 315 | int ret; |
| 316 | |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 317 | cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL); |
| 318 | if (!cpu) |
| 319 | return -ENOMEM; |
| 320 | |
| 321 | dai_link->cpus = cpu; |
| 322 | dai_link->num_cpus = 1; |
| 323 | |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 324 | ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node, |
| 325 | &dai_link->cpus->dai_name); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 326 | if (ret) |
| 327 | return ret; |
| 328 | |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 329 | if (axg_card_cpu_is_playback_fe(dai_link->cpus->of_node)) |
Jerome Brunet | da3f23f | 2020-07-31 14:06:03 +0200 | [diff] [blame] | 330 | return meson_card_set_fe_link(card, dai_link, np, true); |
Kuninori Morimoto | c84836d | 2019-06-06 13:16:32 +0900 | [diff] [blame] | 331 | else if (axg_card_cpu_is_capture_fe(dai_link->cpus->of_node)) |
Jerome Brunet | da3f23f | 2020-07-31 14:06:03 +0200 | [diff] [blame] | 332 | return meson_card_set_fe_link(card, dai_link, np, false); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 333 | |
Jerome Brunet | da3f23f | 2020-07-31 14:06:03 +0200 | [diff] [blame] | 334 | |
| 335 | ret = meson_card_set_be_link(card, dai_link, np); |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 336 | if (ret) |
| 337 | return ret; |
| 338 | |
Jerome Brunet | da3f23f | 2020-07-31 14:06:03 +0200 | [diff] [blame] | 339 | if (axg_card_cpu_is_codec(dai_link->cpus->of_node)) { |
Jerome Brunet | 0a8f111 | 2019-05-15 15:18:57 +0200 | [diff] [blame] | 340 | dai_link->params = &codec_params; |
Jerome Brunet | da3f23f | 2020-07-31 14:06:03 +0200 | [diff] [blame] | 341 | } else { |
| 342 | dai_link->no_pcm = 1; |
| 343 | snd_soc_dai_link_set_capabilities(dai_link); |
| 344 | if (axg_card_cpu_is_tdm_iface(dai_link->cpus->of_node)) |
| 345 | ret = axg_card_parse_tdm(card, np, index); |
Jerome Brunet | 1164284 | 2020-04-20 13:45:10 +0200 | [diff] [blame] | 346 | } |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 347 | |
| 348 | return ret; |
| 349 | } |
| 350 | |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 351 | static const struct meson_card_match_data axg_card_match_data = { |
| 352 | .add_link = axg_card_add_link, |
| 353 | }; |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 354 | |
| 355 | static const struct of_device_id axg_card_of_match[] = { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 356 | { |
| 357 | .compatible = "amlogic,axg-sound-card", |
| 358 | .data = &axg_card_match_data, |
| 359 | }, {} |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 360 | }; |
| 361 | MODULE_DEVICE_TABLE(of, axg_card_of_match); |
| 362 | |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 363 | static struct platform_driver axg_card_pdrv = { |
Jerome Brunet | aa9c3b7 | 2020-02-13 16:51:57 +0100 | [diff] [blame] | 364 | .probe = meson_card_probe, |
| 365 | .remove = meson_card_remove, |
Jerome Brunet | 7864a79 | 2018-07-17 17:43:04 +0200 | [diff] [blame] | 366 | .driver = { |
| 367 | .name = "axg-sound-card", |
| 368 | .of_match_table = axg_card_of_match, |
| 369 | }, |
| 370 | }; |
| 371 | module_platform_driver(axg_card_pdrv); |
| 372 | |
| 373 | MODULE_DESCRIPTION("Amlogic AXG ALSA machine driver"); |
| 374 | MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); |
| 375 | MODULE_LICENSE("GPL v2"); |