--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dice-tc_electronic.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) 2018 Takashi Sakamoto
+ */
+
+#include "dice.h"
+
+struct dice_tc_spec {
+       unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+       unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
+       bool has_midi;
+};
+
+static const struct dice_tc_spec desktop_konnekt6 = {
+       .tx_pcm_chs = {{6, 6, 2}, {0, 0, 0} },
+       .rx_pcm_chs = {{6, 6, 4}, {0, 0, 0} },
+       .has_midi = false,
+};
+
+static const struct dice_tc_spec impact_twin = {
+       .tx_pcm_chs = {{14, 10, 6}, {0, 0, 0} },
+       .rx_pcm_chs = {{14, 10, 6}, {0, 0, 0} },
+       .has_midi = true,
+};
+
+static const struct dice_tc_spec konnekt_8 = {
+       .tx_pcm_chs = {{4, 4, 3}, {0, 0, 0} },
+       .rx_pcm_chs = {{4, 4, 3}, {0, 0, 0} },
+       .has_midi = true,
+};
+
+static const struct dice_tc_spec konnekt_24d = {
+       .tx_pcm_chs = {{16, 16, 6}, {0, 0, 0} },
+       .rx_pcm_chs = {{16, 16, 6}, {0, 0, 0} },
+       .has_midi = true,
+};
+
+static const struct dice_tc_spec konnekt_live = {
+       .tx_pcm_chs = {{16, 16, 16}, {0, 0, 0} },
+       .rx_pcm_chs = {{16, 16, 16}, {0, 0, 0} },
+       .has_midi = true,
+};
+
+static const struct dice_tc_spec studio_konnekt_48 = {
+       .tx_pcm_chs = {{16, 16, 16}, {16, 16, 0} },
+       .rx_pcm_chs = {{16, 16, 16}, {16, 16, 0} },
+       .has_midi = true,
+};
+
+int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice)
+{
+       static const struct {
+               u32 model_id;
+               const struct dice_tc_spec *spec;
+       } *entry, entries[] = {
+               {0x00000020, &konnekt_24d},
+               {0x00000021, &konnekt_8},
+               {0x00000022, &studio_konnekt_48},
+               {0x00000023, &konnekt_live},
+               {0x00000024, &desktop_konnekt6},
+               {0x00000027, &impact_twin},
+       };
+       struct fw_csr_iterator it;
+       int key, val, model_id;
+       int i;
+
+       model_id = 0;
+       fw_csr_iterator_init(&it, dice->unit->directory);
+       while (fw_csr_iterator_next(&it, &key, &val)) {
+               if (key == CSR_MODEL) {
+                       model_id = val;
+                       break;
+               }
+       }
+
+       entry = NULL;
+       for (i = 0; i < ARRAY_SIZE(entries); ++i) {
+               entry = entries + i;
+               if (entry->model_id == model_id)
+                       break;
+       }
+       if (!entry)
+               return -ENODEV;
+
+       memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs,
+              MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+       memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs,
+              MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
+
+       for (i = 0; i < MAX_STREAMS; ++i) {
+               if (entry->spec->has_midi) {
+                       dice->tx_midi_ports[i] = 1;
+                       dice->rx_midi_ports[i] = 1;
+               }
+       }
+
+       return 0;
+}
 
 
        dice_card_strings(dice);
 
-       err = snd_dice_stream_detect_current_formats(dice);
+       err = dice->detect_formats(dice);
        if (err < 0)
                goto error;
 
                 "Sound card registration failed: %d\n", err);
 }
 
-static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+static int dice_probe(struct fw_unit *unit,
+                     const struct ieee1394_device_id *entry)
 {
        struct snd_dice *dice;
        int err;
 
-       err = check_dice_category(unit);
-       if (err < 0)
-               return -ENODEV;
+       if (!entry->driver_data) {
+               err = check_dice_category(unit);
+               if (err < 0)
+                       return -ENODEV;
+       }
 
        /* Allocate this independent of sound card instance. */
        dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
        dice->unit = fw_unit_get(unit);
        dev_set_drvdata(&unit->device, dice);
 
+       if (!entry->driver_data) {
+               dice->detect_formats = snd_dice_stream_detect_current_formats;
+       } else {
+               dice->detect_formats =
+                               (snd_dice_detect_formats_t)entry->driver_data;
+       }
+
        spin_lock_init(&dice->lock);
        mutex_init(&dice->mutex);
        init_completion(&dice->clock_accepted);
 #define DICE_INTERFACE 0x000001
 
 static const struct ieee1394_device_id dice_id_table[] = {
-       {
-               .match_flags = IEEE1394_MATCH_VERSION,
-               .version     = DICE_INTERFACE,
-       },
        /* M-Audio Profire 610/2626 has a different value in version field. */
        {
                .match_flags    = IEEE1394_MATCH_VENDOR_ID |
                .vendor_id      = 0x000d6c,
                .specifier_id   = 0x000d6c,
        },
+       /* TC Electronic Konnekt 24D. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000020,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       /* TC Electronic Konnekt 8. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000021,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       /* TC Electronic Studio Konnekt 48. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000022,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       /* TC Electronic Konnekt Live. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000023,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       /* TC Electronic Desktop Konnekt 6. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000024,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       /* TC Electronic Impact Twin. */
+       {
+               .match_flags    = IEEE1394_MATCH_VENDOR_ID |
+                                 IEEE1394_MATCH_MODEL_ID,
+               .vendor_id      = OUI_TCELECTRONIC,
+               .model_id       = 0x000027,
+               .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
+       },
+       {
+               .match_flags = IEEE1394_MATCH_VERSION,
+               .version     = DICE_INTERFACE,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(ieee1394, dice_id_table);