linux/drivers/hwtracing/intel_th/gth.c
<<
>>
Prefs
   1/*
   2 * Intel(R) Trace Hub Global Trace Hub
   3 *
   4 * Copyright (C) 2014-2015 Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 */
  15
  16#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  17
  18#include <linux/types.h>
  19#include <linux/module.h>
  20#include <linux/device.h>
  21#include <linux/io.h>
  22#include <linux/mm.h>
  23#include <linux/slab.h>
  24#include <linux/bitmap.h>
  25#include <linux/pm_runtime.h>
  26
  27#include "intel_th.h"
  28#include "gth.h"
  29
  30struct gth_device;
  31
  32/**
  33 * struct gth_output - GTH view on an output port
  34 * @gth:        backlink to the GTH device
  35 * @output:     link to output device's output descriptor
  36 * @index:      output port number
  37 * @port_type:  one of GTH_* port type values
  38 * @master:     bitmap of masters configured for this output
  39 */
  40struct gth_output {
  41        struct gth_device       *gth;
  42        struct intel_th_output  *output;
  43        unsigned int            index;
  44        unsigned int            port_type;
  45        DECLARE_BITMAP(master, TH_CONFIGURABLE_MASTERS + 1);
  46};
  47
  48/**
  49 * struct gth_device - GTH device
  50 * @dev:        driver core's device
  51 * @base:       register window base address
  52 * @output_group:       attributes describing output ports
  53 * @master_group:       attributes describing master assignments
  54 * @output:             output ports
  55 * @master:             master/output port assignments
  56 * @gth_lock:           serializes accesses to GTH bits
  57 */
  58struct gth_device {
  59        struct device           *dev;
  60        void __iomem            *base;
  61
  62        struct attribute_group  output_group;
  63        struct attribute_group  master_group;
  64        struct gth_output       output[TH_POSSIBLE_OUTPUTS];
  65        signed char             master[TH_CONFIGURABLE_MASTERS + 1];
  66        spinlock_t              gth_lock;
  67};
  68
  69static void gth_output_set(struct gth_device *gth, int port,
  70                           unsigned int config)
  71{
  72        unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
  73        u32 val;
  74        int shift = (port & 3) * 8;
  75
  76        val = ioread32(gth->base + reg);
  77        val &= ~(0xff << shift);
  78        val |= config << shift;
  79        iowrite32(val, gth->base + reg);
  80}
  81
  82static unsigned int gth_output_get(struct gth_device *gth, int port)
  83{
  84        unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
  85        u32 val;
  86        int shift = (port & 3) * 8;
  87
  88        val = ioread32(gth->base + reg);
  89        val &= 0xff << shift;
  90        val >>= shift;
  91
  92        return val;
  93}
  94
  95static void gth_smcfreq_set(struct gth_device *gth, int port,
  96                            unsigned int freq)
  97{
  98        unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
  99        int shift = (port & 1) * 16;
 100        u32 val;
 101
 102        val = ioread32(gth->base + reg);
 103        val &= ~(0xffff << shift);
 104        val |= freq << shift;
 105        iowrite32(val, gth->base + reg);
 106}
 107
 108static unsigned int gth_smcfreq_get(struct gth_device *gth, int port)
 109{
 110        unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
 111        int shift = (port & 1) * 16;
 112        u32 val;
 113
 114        val = ioread32(gth->base + reg);
 115        val &= 0xffff << shift;
 116        val >>= shift;
 117
 118        return val;
 119}
 120
 121/*
 122 * "masters" attribute group
 123 */
 124
 125struct master_attribute {
 126        struct device_attribute attr;
 127        struct gth_device       *gth;
 128        unsigned int            master;
 129};
 130
 131static void
 132gth_master_set(struct gth_device *gth, unsigned int master, int port)
 133{
 134        unsigned int reg = REG_GTH_SWDEST0 + ((master >> 1) & ~3u);
 135        unsigned int shift = (master & 0x7) * 4;
 136        u32 val;
 137
 138        if (master >= 256) {
 139                reg = REG_GTH_GSWTDEST;
 140                shift = 0;
 141        }
 142
 143        val = ioread32(gth->base + reg);
 144        val &= ~(0xf << shift);
 145        if (port >= 0)
 146                val |= (0x8 | port) << shift;
 147        iowrite32(val, gth->base + reg);
 148}
 149
 150static ssize_t master_attr_show(struct device *dev,
 151                                struct device_attribute *attr,
 152                                char *buf)
 153{
 154        struct master_attribute *ma =
 155                container_of(attr, struct master_attribute, attr);
 156        struct gth_device *gth = ma->gth;
 157        size_t count;
 158        int port;
 159
 160        spin_lock(&gth->gth_lock);
 161        port = gth->master[ma->master];
 162        spin_unlock(&gth->gth_lock);
 163
 164        if (port >= 0)
 165                count = snprintf(buf, PAGE_SIZE, "%x\n", port);
 166        else
 167                count = snprintf(buf, PAGE_SIZE, "disabled\n");
 168
 169        return count;
 170}
 171
 172static ssize_t master_attr_store(struct device *dev,
 173                                 struct device_attribute *attr,
 174                                 const char *buf, size_t count)
 175{
 176        struct master_attribute *ma =
 177                container_of(attr, struct master_attribute, attr);
 178        struct gth_device *gth = ma->gth;
 179        int old_port, port;
 180
 181        if (kstrtoint(buf, 10, &port) < 0)
 182                return -EINVAL;
 183
 184        if (port >= TH_POSSIBLE_OUTPUTS || port < -1)
 185                return -EINVAL;
 186
 187        spin_lock(&gth->gth_lock);
 188
 189        /* disconnect from the previous output port, if any */
 190        old_port = gth->master[ma->master];
 191        if (old_port >= 0) {
 192                gth->master[ma->master] = -1;
 193                clear_bit(ma->master, gth->output[old_port].master);
 194
 195                /*
 196                 * if the port is active, program this setting,
 197                 * implies that runtime PM is on
 198                 */
 199                if (gth->output[old_port].output->active)
 200                        gth_master_set(gth, ma->master, -1);
 201        }
 202
 203        /* connect to the new output port, if any */
 204        if (port >= 0) {
 205                /* check if there's a driver for this port */
 206                if (!gth->output[port].output) {
 207                        count = -ENODEV;
 208                        goto unlock;
 209                }
 210
 211                set_bit(ma->master, gth->output[port].master);
 212
 213                /* if the port is active, program this setting, see above */
 214                if (gth->output[port].output->active)
 215                        gth_master_set(gth, ma->master, port);
 216        }
 217
 218        gth->master[ma->master] = port;
 219
 220unlock:
 221        spin_unlock(&gth->gth_lock);
 222
 223        return count;
 224}
 225
 226struct output_attribute {
 227        struct device_attribute attr;
 228        struct gth_device       *gth;
 229        unsigned int            port;
 230        unsigned int            parm;
 231};
 232
 233#define OUTPUT_PARM(_name, _mask, _r, _w, _what)                        \
 234        [TH_OUTPUT_PARM(_name)] = { .name = __stringify(_name),         \
 235                                    .get = gth_ ## _what ## _get,       \
 236                                    .set = gth_ ## _what ## _set,       \
 237                                    .mask = (_mask),                    \
 238                                    .readable = (_r),                   \
 239                                    .writable = (_w) }
 240
 241static const struct output_parm {
 242        const char      *name;
 243        unsigned int    (*get)(struct gth_device *gth, int port);
 244        void            (*set)(struct gth_device *gth, int port,
 245                               unsigned int val);
 246        unsigned int    mask;
 247        unsigned int    readable : 1,
 248                        writable : 1;
 249} output_parms[] = {
 250        OUTPUT_PARM(port,       0x7,    1, 0, output),
 251        OUTPUT_PARM(null,       BIT(3), 1, 1, output),
 252        OUTPUT_PARM(drop,       BIT(4), 1, 1, output),
 253        OUTPUT_PARM(reset,      BIT(5), 1, 0, output),
 254        OUTPUT_PARM(flush,      BIT(7), 0, 1, output),
 255        OUTPUT_PARM(smcfreq,    0xffff, 1, 1, smcfreq),
 256};
 257
 258static void
 259gth_output_parm_set(struct gth_device *gth, int port, unsigned int parm,
 260                    unsigned int val)
 261{
 262        unsigned int config = output_parms[parm].get(gth, port);
 263        unsigned int mask = output_parms[parm].mask;
 264        unsigned int shift = __ffs(mask);
 265
 266        config &= ~mask;
 267        config |= (val << shift) & mask;
 268        output_parms[parm].set(gth, port, config);
 269}
 270
 271static unsigned int
 272gth_output_parm_get(struct gth_device *gth, int port, unsigned int parm)
 273{
 274        unsigned int config = output_parms[parm].get(gth, port);
 275        unsigned int mask = output_parms[parm].mask;
 276        unsigned int shift = __ffs(mask);
 277
 278        config &= mask;
 279        config >>= shift;
 280        return config;
 281}
 282
 283/*
 284 * Reset outputs and sources
 285 */
 286static int intel_th_gth_reset(struct gth_device *gth)
 287{
 288        u32 scratchpad;
 289        int port, i;
 290
 291        scratchpad = ioread32(gth->base + REG_GTH_SCRPD0);
 292        if (scratchpad & SCRPD_DEBUGGER_IN_USE)
 293                return -EBUSY;
 294
 295        /* Always save/restore STH and TU registers in S0ix entry/exit */
 296        scratchpad |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED;
 297        iowrite32(scratchpad, gth->base + REG_GTH_SCRPD0);
 298
 299        /* output ports */
 300        for (port = 0; port < 8; port++) {
 301                if (gth_output_parm_get(gth, port, TH_OUTPUT_PARM(port)) ==
 302                    GTH_NONE)
 303                        continue;
 304
 305                gth_output_set(gth, port, 0);
 306                gth_smcfreq_set(gth, port, 16);
 307        }
 308        /* disable overrides */
 309        iowrite32(0, gth->base + REG_GTH_DESTOVR);
 310
 311        /* masters swdest_0~31 and gswdest */
 312        for (i = 0; i < 33; i++)
 313                iowrite32(0, gth->base + REG_GTH_SWDEST0 + i * 4);
 314
 315        /* sources */
 316        iowrite32(0, gth->base + REG_GTH_SCR);
 317        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 318
 319        return 0;
 320}
 321
 322/*
 323 * "outputs" attribute group
 324 */
 325
 326static ssize_t output_attr_show(struct device *dev,
 327                                struct device_attribute *attr,
 328                                char *buf)
 329{
 330        struct output_attribute *oa =
 331                container_of(attr, struct output_attribute, attr);
 332        struct gth_device *gth = oa->gth;
 333        size_t count;
 334
 335        pm_runtime_get_sync(dev);
 336
 337        spin_lock(&gth->gth_lock);
 338        count = snprintf(buf, PAGE_SIZE, "%x\n",
 339                         gth_output_parm_get(gth, oa->port, oa->parm));
 340        spin_unlock(&gth->gth_lock);
 341
 342        pm_runtime_put(dev);
 343
 344        return count;
 345}
 346
 347static ssize_t output_attr_store(struct device *dev,
 348                                 struct device_attribute *attr,
 349                                 const char *buf, size_t count)
 350{
 351        struct output_attribute *oa =
 352                container_of(attr, struct output_attribute, attr);
 353        struct gth_device *gth = oa->gth;
 354        unsigned int config;
 355
 356        if (kstrtouint(buf, 16, &config) < 0)
 357                return -EINVAL;
 358
 359        pm_runtime_get_sync(dev);
 360
 361        spin_lock(&gth->gth_lock);
 362        gth_output_parm_set(gth, oa->port, oa->parm, config);
 363        spin_unlock(&gth->gth_lock);
 364
 365        pm_runtime_put(dev);
 366
 367        return count;
 368}
 369
 370static int intel_th_master_attributes(struct gth_device *gth)
 371{
 372        struct master_attribute *master_attrs;
 373        struct attribute **attrs;
 374        int i, nattrs = TH_CONFIGURABLE_MASTERS + 2;
 375
 376        attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
 377        if (!attrs)
 378                return -ENOMEM;
 379
 380        master_attrs = devm_kcalloc(gth->dev, nattrs,
 381                                    sizeof(struct master_attribute),
 382                                    GFP_KERNEL);
 383        if (!master_attrs)
 384                return -ENOMEM;
 385
 386        for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) {
 387                char *name;
 388
 389                name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d%s", i,
 390                                      i == TH_CONFIGURABLE_MASTERS ? "+" : "");
 391                if (!name)
 392                        return -ENOMEM;
 393
 394                master_attrs[i].attr.attr.name = name;
 395                master_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
 396                master_attrs[i].attr.show = master_attr_show;
 397                master_attrs[i].attr.store = master_attr_store;
 398
 399                sysfs_attr_init(&master_attrs[i].attr.attr);
 400                attrs[i] = &master_attrs[i].attr.attr;
 401
 402                master_attrs[i].gth = gth;
 403                master_attrs[i].master = i;
 404        }
 405
 406        gth->master_group.name  = "masters";
 407        gth->master_group.attrs = attrs;
 408
 409        return sysfs_create_group(&gth->dev->kobj, &gth->master_group);
 410}
 411
 412static int intel_th_output_attributes(struct gth_device *gth)
 413{
 414        struct output_attribute *out_attrs;
 415        struct attribute **attrs;
 416        int i, j, nouts = TH_POSSIBLE_OUTPUTS;
 417        int nparms = ARRAY_SIZE(output_parms);
 418        int nattrs = nouts * nparms + 1;
 419
 420        attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
 421        if (!attrs)
 422                return -ENOMEM;
 423
 424        out_attrs = devm_kcalloc(gth->dev, nattrs,
 425                                 sizeof(struct output_attribute),
 426                                 GFP_KERNEL);
 427        if (!out_attrs)
 428                return -ENOMEM;
 429
 430        for (i = 0; i < nouts; i++) {
 431                for (j = 0; j < nparms; j++) {
 432                        unsigned int idx = i * nparms + j;
 433                        char *name;
 434
 435                        name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d_%s", i,
 436                                              output_parms[j].name);
 437                        if (!name)
 438                                return -ENOMEM;
 439
 440                        out_attrs[idx].attr.attr.name = name;
 441
 442                        if (output_parms[j].readable) {
 443                                out_attrs[idx].attr.attr.mode |= S_IRUGO;
 444                                out_attrs[idx].attr.show = output_attr_show;
 445                        }
 446
 447                        if (output_parms[j].writable) {
 448                                out_attrs[idx].attr.attr.mode |= S_IWUSR;
 449                                out_attrs[idx].attr.store = output_attr_store;
 450                        }
 451
 452                        sysfs_attr_init(&out_attrs[idx].attr.attr);
 453                        attrs[idx] = &out_attrs[idx].attr.attr;
 454
 455                        out_attrs[idx].gth = gth;
 456                        out_attrs[idx].port = i;
 457                        out_attrs[idx].parm = j;
 458                }
 459        }
 460
 461        gth->output_group.name  = "outputs";
 462        gth->output_group.attrs = attrs;
 463
 464        return sysfs_create_group(&gth->dev->kobj, &gth->output_group);
 465}
 466
 467/**
 468 * intel_th_gth_disable() - disable tracing to an output device
 469 * @thdev:      GTH device
 470 * @output:     output device's descriptor
 471 *
 472 * This will deconfigure all masters set to output to this device,
 473 * disable tracing using force storeEn off signal and wait for the
 474 * "pipeline empty" bit for corresponding output port.
 475 */
 476static void intel_th_gth_disable(struct intel_th_device *thdev,
 477                                 struct intel_th_output *output)
 478{
 479        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 480        unsigned long count;
 481        int master;
 482        u32 reg;
 483
 484        spin_lock(&gth->gth_lock);
 485        output->active = false;
 486
 487        for_each_set_bit(master, gth->output[output->port].master,
 488                         TH_CONFIGURABLE_MASTERS) {
 489                gth_master_set(gth, master, -1);
 490        }
 491        spin_unlock(&gth->gth_lock);
 492
 493        iowrite32(0, gth->base + REG_GTH_SCR);
 494        iowrite32(0xfd, gth->base + REG_GTH_SCR2);
 495
 496        /* wait on pipeline empty for the given port */
 497        for (reg = 0, count = GTH_PLE_WAITLOOP_DEPTH;
 498             count && !(reg & BIT(output->port)); count--) {
 499                reg = ioread32(gth->base + REG_GTH_STAT);
 500                cpu_relax();
 501        }
 502
 503        /* clear force capture done for next captures */
 504        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 505
 506        if (!count)
 507                dev_dbg(&thdev->dev, "timeout waiting for GTH[%d] PLE\n",
 508                        output->port);
 509
 510        reg = ioread32(gth->base + REG_GTH_SCRPD0);
 511        reg &= ~output->scratchpad;
 512        iowrite32(reg, gth->base + REG_GTH_SCRPD0);
 513}
 514
 515/**
 516 * intel_th_gth_enable() - enable tracing to an output device
 517 * @thdev:      GTH device
 518 * @output:     output device's descriptor
 519 *
 520 * This will configure all masters set to output to this device and
 521 * enable tracing using force storeEn signal.
 522 */
 523static void intel_th_gth_enable(struct intel_th_device *thdev,
 524                                struct intel_th_output *output)
 525{
 526        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 527        u32 scr = 0xfc0000, scrpd;
 528        int master;
 529
 530        spin_lock(&gth->gth_lock);
 531        for_each_set_bit(master, gth->output[output->port].master,
 532                         TH_CONFIGURABLE_MASTERS + 1) {
 533                gth_master_set(gth, master, output->port);
 534        }
 535
 536        if (output->multiblock)
 537                scr |= 0xff;
 538
 539        output->active = true;
 540        spin_unlock(&gth->gth_lock);
 541
 542        scrpd = ioread32(gth->base + REG_GTH_SCRPD0);
 543        scrpd |= output->scratchpad;
 544        iowrite32(scrpd, gth->base + REG_GTH_SCRPD0);
 545
 546        iowrite32(scr, gth->base + REG_GTH_SCR);
 547        iowrite32(0, gth->base + REG_GTH_SCR2);
 548}
 549
 550/**
 551 * intel_th_gth_assign() - assign output device to a GTH output port
 552 * @thdev:      GTH device
 553 * @othdev:     output device
 554 *
 555 * This will match a given output device parameters against present
 556 * output ports on the GTH and fill out relevant bits in output device's
 557 * descriptor.
 558 *
 559 * Return:      0 on success, -errno on error.
 560 */
 561static int intel_th_gth_assign(struct intel_th_device *thdev,
 562                               struct intel_th_device *othdev)
 563{
 564        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 565        int i, id;
 566
 567        if (thdev->host_mode)
 568                return -EBUSY;
 569
 570        if (othdev->type != INTEL_TH_OUTPUT)
 571                return -EINVAL;
 572
 573        for (i = 0, id = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
 574                if (gth->output[i].port_type != othdev->output.type)
 575                        continue;
 576
 577                if (othdev->id == -1 || othdev->id == id)
 578                        goto found;
 579
 580                id++;
 581        }
 582
 583        return -ENOENT;
 584
 585found:
 586        spin_lock(&gth->gth_lock);
 587        othdev->output.port = i;
 588        othdev->output.active = false;
 589        gth->output[i].output = &othdev->output;
 590        spin_unlock(&gth->gth_lock);
 591
 592        return 0;
 593}
 594
 595/**
 596 * intel_th_gth_unassign() - deassociate an output device from its output port
 597 * @thdev:      GTH device
 598 * @othdev:     output device
 599 */
 600static void intel_th_gth_unassign(struct intel_th_device *thdev,
 601                                  struct intel_th_device *othdev)
 602{
 603        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 604        int port = othdev->output.port;
 605
 606        if (thdev->host_mode)
 607                return;
 608
 609        spin_lock(&gth->gth_lock);
 610        othdev->output.port = -1;
 611        othdev->output.active = false;
 612        gth->output[port].output = NULL;
 613        spin_unlock(&gth->gth_lock);
 614}
 615
 616static int
 617intel_th_gth_set_output(struct intel_th_device *thdev, unsigned int master)
 618{
 619        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 620        int port = 0; /* FIXME: make default output configurable */
 621
 622        /*
 623         * everything above TH_CONFIGURABLE_MASTERS is controlled by the
 624         * same register
 625         */
 626        if (master > TH_CONFIGURABLE_MASTERS)
 627                master = TH_CONFIGURABLE_MASTERS;
 628
 629        spin_lock(&gth->gth_lock);
 630        if (gth->master[master] == -1) {
 631                set_bit(master, gth->output[port].master);
 632                gth->master[master] = port;
 633        }
 634        spin_unlock(&gth->gth_lock);
 635
 636        return 0;
 637}
 638
 639static int intel_th_gth_probe(struct intel_th_device *thdev)
 640{
 641        struct device *dev = &thdev->dev;
 642        struct gth_device *gth;
 643        struct resource *res;
 644        void __iomem *base;
 645        int i, ret;
 646
 647        res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
 648        if (!res)
 649                return -ENODEV;
 650
 651        base = devm_ioremap(dev, res->start, resource_size(res));
 652        if (!base)
 653                return -ENOMEM;
 654
 655        gth = devm_kzalloc(dev, sizeof(*gth), GFP_KERNEL);
 656        if (!gth)
 657                return -ENOMEM;
 658
 659        gth->dev = dev;
 660        gth->base = base;
 661        spin_lock_init(&gth->gth_lock);
 662
 663        /*
 664         * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE
 665         * bit. Either way, don't reset HW in this case, and don't export any
 666         * capture configuration attributes. Also, refuse to assign output
 667         * drivers to ports, see intel_th_gth_assign().
 668         */
 669        if (thdev->host_mode)
 670                goto done;
 671
 672        ret = intel_th_gth_reset(gth);
 673        if (ret) {
 674                if (ret != -EBUSY)
 675                        return ret;
 676
 677                thdev->host_mode = true;
 678
 679                goto done;
 680        }
 681
 682        for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++)
 683                gth->master[i] = -1;
 684
 685        for (i = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
 686                gth->output[i].gth = gth;
 687                gth->output[i].index = i;
 688                gth->output[i].port_type =
 689                        gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port));
 690        }
 691
 692        if (intel_th_output_attributes(gth) ||
 693            intel_th_master_attributes(gth)) {
 694                pr_warn("Can't initialize sysfs attributes\n");
 695
 696                if (gth->output_group.attrs)
 697                        sysfs_remove_group(&gth->dev->kobj, &gth->output_group);
 698                return -ENOMEM;
 699        }
 700
 701done:
 702        dev_set_drvdata(dev, gth);
 703
 704        return 0;
 705}
 706
 707static void intel_th_gth_remove(struct intel_th_device *thdev)
 708{
 709        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 710
 711        sysfs_remove_group(&gth->dev->kobj, &gth->output_group);
 712        sysfs_remove_group(&gth->dev->kobj, &gth->master_group);
 713}
 714
 715static struct intel_th_driver intel_th_gth_driver = {
 716        .probe          = intel_th_gth_probe,
 717        .remove         = intel_th_gth_remove,
 718        .assign         = intel_th_gth_assign,
 719        .unassign       = intel_th_gth_unassign,
 720        .set_output     = intel_th_gth_set_output,
 721        .enable         = intel_th_gth_enable,
 722        .disable        = intel_th_gth_disable,
 723        .driver = {
 724                .name   = "gth",
 725                .owner  = THIS_MODULE,
 726        },
 727};
 728
 729module_driver(intel_th_gth_driver,
 730              intel_th_driver_register,
 731              intel_th_driver_unregister);
 732
 733MODULE_ALIAS("intel_th_switch");
 734MODULE_LICENSE("GPL v2");
 735MODULE_DESCRIPTION("Intel(R) Trace Hub Global Trace Hub driver");
 736MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
 737