linux/drivers/hsi/controllers/omap_ssi_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* OMAP SSI driver.
   3 *
   4 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
   5 * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org>
   6 *
   7 * Contact: Carlos Chinea <carlos.chinea@nokia.com>
   8 */
   9
  10#include <linux/compiler.h>
  11#include <linux/err.h>
  12#include <linux/ioport.h>
  13#include <linux/io.h>
  14#include <linux/clk.h>
  15#include <linux/device.h>
  16#include <linux/platform_device.h>
  17#include <linux/dma-mapping.h>
  18#include <linux/dmaengine.h>
  19#include <linux/delay.h>
  20#include <linux/seq_file.h>
  21#include <linux/scatterlist.h>
  22#include <linux/interrupt.h>
  23#include <linux/spinlock.h>
  24#include <linux/debugfs.h>
  25#include <linux/pinctrl/consumer.h>
  26#include <linux/pm_runtime.h>
  27#include <linux/of_platform.h>
  28#include <linux/hsi/hsi.h>
  29#include <linux/idr.h>
  30
  31#include "omap_ssi_regs.h"
  32#include "omap_ssi.h"
  33
  34/* For automatically allocated device IDs */
  35static DEFINE_IDA(platform_omap_ssi_ida);
  36
  37#ifdef CONFIG_DEBUG_FS
  38static int ssi_regs_show(struct seq_file *m, void *p __maybe_unused)
  39{
  40        struct hsi_controller *ssi = m->private;
  41        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
  42        void __iomem *sys = omap_ssi->sys;
  43
  44        pm_runtime_get_sync(ssi->device.parent);
  45        seq_printf(m, "REVISION\t: 0x%08x\n",  readl(sys + SSI_REVISION_REG));
  46        seq_printf(m, "SYSCONFIG\t: 0x%08x\n", readl(sys + SSI_SYSCONFIG_REG));
  47        seq_printf(m, "SYSSTATUS\t: 0x%08x\n", readl(sys + SSI_SYSSTATUS_REG));
  48        pm_runtime_put(ssi->device.parent);
  49
  50        return 0;
  51}
  52
  53static int ssi_gdd_regs_show(struct seq_file *m, void *p __maybe_unused)
  54{
  55        struct hsi_controller *ssi = m->private;
  56        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
  57        void __iomem *gdd = omap_ssi->gdd;
  58        void __iomem *sys = omap_ssi->sys;
  59        int lch;
  60
  61        pm_runtime_get_sync(ssi->device.parent);
  62
  63        seq_printf(m, "GDD_MPU_STATUS\t: 0x%08x\n",
  64                readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG));
  65        seq_printf(m, "GDD_MPU_ENABLE\t: 0x%08x\n\n",
  66                readl(sys + SSI_GDD_MPU_IRQ_ENABLE_REG));
  67        seq_printf(m, "HW_ID\t\t: 0x%08x\n",
  68                                readl(gdd + SSI_GDD_HW_ID_REG));
  69        seq_printf(m, "PPORT_ID\t: 0x%08x\n",
  70                                readl(gdd + SSI_GDD_PPORT_ID_REG));
  71        seq_printf(m, "MPORT_ID\t: 0x%08x\n",
  72                                readl(gdd + SSI_GDD_MPORT_ID_REG));
  73        seq_printf(m, "TEST\t\t: 0x%08x\n",
  74                                readl(gdd + SSI_GDD_TEST_REG));
  75        seq_printf(m, "GCR\t\t: 0x%08x\n",
  76                                readl(gdd + SSI_GDD_GCR_REG));
  77
  78        for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
  79                seq_printf(m, "\nGDD LCH %d\n=========\n", lch);
  80                seq_printf(m, "CSDP\t\t: 0x%04x\n",
  81                                readw(gdd + SSI_GDD_CSDP_REG(lch)));
  82                seq_printf(m, "CCR\t\t: 0x%04x\n",
  83                                readw(gdd + SSI_GDD_CCR_REG(lch)));
  84                seq_printf(m, "CICR\t\t: 0x%04x\n",
  85                                readw(gdd + SSI_GDD_CICR_REG(lch)));
  86                seq_printf(m, "CSR\t\t: 0x%04x\n",
  87                                readw(gdd + SSI_GDD_CSR_REG(lch)));
  88                seq_printf(m, "CSSA\t\t: 0x%08x\n",
  89                                readl(gdd + SSI_GDD_CSSA_REG(lch)));
  90                seq_printf(m, "CDSA\t\t: 0x%08x\n",
  91                                readl(gdd + SSI_GDD_CDSA_REG(lch)));
  92                seq_printf(m, "CEN\t\t: 0x%04x\n",
  93                                readw(gdd + SSI_GDD_CEN_REG(lch)));
  94                seq_printf(m, "CSAC\t\t: 0x%04x\n",
  95                                readw(gdd + SSI_GDD_CSAC_REG(lch)));
  96                seq_printf(m, "CDAC\t\t: 0x%04x\n",
  97                                readw(gdd + SSI_GDD_CDAC_REG(lch)));
  98                seq_printf(m, "CLNK_CTRL\t: 0x%04x\n",
  99                                readw(gdd + SSI_GDD_CLNK_CTRL_REG(lch)));
 100        }
 101
 102        pm_runtime_put(ssi->device.parent);
 103
 104        return 0;
 105}
 106
 107DEFINE_SHOW_ATTRIBUTE(ssi_regs);
 108DEFINE_SHOW_ATTRIBUTE(ssi_gdd_regs);
 109
 110static int ssi_debug_add_ctrl(struct hsi_controller *ssi)
 111{
 112        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 113        struct dentry *dir;
 114
 115        /* SSI controller */
 116        omap_ssi->dir = debugfs_create_dir(dev_name(&ssi->device), NULL);
 117        if (!omap_ssi->dir)
 118                return -ENOMEM;
 119
 120        debugfs_create_file("regs", S_IRUGO, omap_ssi->dir, ssi,
 121                                                                &ssi_regs_fops);
 122        /* SSI GDD (DMA) */
 123        dir = debugfs_create_dir("gdd", omap_ssi->dir);
 124        if (!dir)
 125                goto rback;
 126        debugfs_create_file("regs", S_IRUGO, dir, ssi, &ssi_gdd_regs_fops);
 127
 128        return 0;
 129rback:
 130        debugfs_remove_recursive(omap_ssi->dir);
 131
 132        return -ENOMEM;
 133}
 134
 135static void ssi_debug_remove_ctrl(struct hsi_controller *ssi)
 136{
 137        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 138
 139        debugfs_remove_recursive(omap_ssi->dir);
 140}
 141#endif /* CONFIG_DEBUG_FS */
 142
 143/*
 144 * FIXME: Horrible HACK needed until we remove the useless wakeline test
 145 * in the CMT. To be removed !!!!
 146 */
 147void ssi_waketest(struct hsi_client *cl, unsigned int enable)
 148{
 149        struct hsi_port *port = hsi_get_port(cl);
 150        struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
 151        struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
 152        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 153
 154        omap_port->wktest = !!enable;
 155        if (omap_port->wktest) {
 156                pm_runtime_get_sync(ssi->device.parent);
 157                writel_relaxed(SSI_WAKE(0),
 158                                omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
 159        } else {
 160                writel_relaxed(SSI_WAKE(0),
 161                                omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
 162                pm_runtime_put(ssi->device.parent);
 163        }
 164}
 165EXPORT_SYMBOL_GPL(ssi_waketest);
 166
 167static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch)
 168{
 169        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 170        struct hsi_msg *msg = omap_ssi->gdd_trn[lch].msg;
 171        struct hsi_port *port = to_hsi_port(msg->cl->device.parent);
 172        struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
 173        unsigned int dir;
 174        u32 csr;
 175        u32 val;
 176
 177        spin_lock(&omap_ssi->lock);
 178
 179        val = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
 180        val &= ~SSI_GDD_LCH(lch);
 181        writel_relaxed(val, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);
 182
 183        if (msg->ttype == HSI_MSG_READ) {
 184                dir = DMA_FROM_DEVICE;
 185                val = SSI_DATAAVAILABLE(msg->channel);
 186                pm_runtime_put(omap_port->pdev);
 187        } else {
 188                dir = DMA_TO_DEVICE;
 189                val = SSI_DATAACCEPT(msg->channel);
 190                /* Keep clocks reference for write pio event */
 191        }
 192        dma_unmap_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents, dir);
 193        csr = readw(omap_ssi->gdd + SSI_GDD_CSR_REG(lch));
 194        omap_ssi->gdd_trn[lch].msg = NULL; /* release GDD lch */
 195        dev_dbg(&port->device, "DMA completed ch %d ttype %d\n",
 196                                msg->channel, msg->ttype);
 197        spin_unlock(&omap_ssi->lock);
 198        if (csr & SSI_CSR_TOUR) { /* Timeout error */
 199                msg->status = HSI_STATUS_ERROR;
 200                msg->actual_len = 0;
 201                spin_lock(&omap_port->lock);
 202                list_del(&msg->link); /* Dequeue msg */
 203                spin_unlock(&omap_port->lock);
 204
 205                list_add_tail(&msg->link, &omap_port->errqueue);
 206                schedule_delayed_work(&omap_port->errqueue_work, 0);
 207                return;
 208        }
 209        spin_lock(&omap_port->lock);
 210        val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
 211        writel_relaxed(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));
 212        spin_unlock(&omap_port->lock);
 213
 214        msg->status = HSI_STATUS_COMPLETED;
 215        msg->actual_len = sg_dma_len(msg->sgt.sgl);
 216}
 217
 218static void ssi_gdd_tasklet(unsigned long dev)
 219{
 220        struct hsi_controller *ssi = (struct hsi_controller *)dev;
 221        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 222        void __iomem *sys = omap_ssi->sys;
 223        unsigned int lch;
 224        u32 status_reg;
 225
 226        pm_runtime_get(ssi->device.parent);
 227
 228        if (!pm_runtime_active(ssi->device.parent)) {
 229                dev_warn(ssi->device.parent, "ssi_gdd_tasklet called without runtime PM!\n");
 230                pm_runtime_put(ssi->device.parent);
 231                return;
 232        }
 233
 234        status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
 235        for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++) {
 236                if (status_reg & SSI_GDD_LCH(lch))
 237                        ssi_gdd_complete(ssi, lch);
 238        }
 239        writel_relaxed(status_reg, sys + SSI_GDD_MPU_IRQ_STATUS_REG);
 240        status_reg = readl(sys + SSI_GDD_MPU_IRQ_STATUS_REG);
 241
 242        pm_runtime_put(ssi->device.parent);
 243
 244        if (status_reg)
 245                tasklet_hi_schedule(&omap_ssi->gdd_tasklet);
 246        else
 247                enable_irq(omap_ssi->gdd_irq);
 248
 249}
 250
 251static irqreturn_t ssi_gdd_isr(int irq, void *ssi)
 252{
 253        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 254
 255        tasklet_hi_schedule(&omap_ssi->gdd_tasklet);
 256        disable_irq_nosync(irq);
 257
 258        return IRQ_HANDLED;
 259}
 260
 261static unsigned long ssi_get_clk_rate(struct hsi_controller *ssi)
 262{
 263        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 264        unsigned long rate = clk_get_rate(omap_ssi->fck);
 265        return rate;
 266}
 267
 268static int ssi_clk_event(struct notifier_block *nb, unsigned long event,
 269                                                                void *data)
 270{
 271        struct omap_ssi_controller *omap_ssi = container_of(nb,
 272                                        struct omap_ssi_controller, fck_nb);
 273        struct hsi_controller *ssi = to_hsi_controller(omap_ssi->dev);
 274        struct clk_notifier_data *clk_data = data;
 275        struct omap_ssi_port *omap_port;
 276        int i;
 277
 278        switch (event) {
 279        case PRE_RATE_CHANGE:
 280                dev_dbg(&ssi->device, "pre rate change\n");
 281
 282                for (i = 0; i < ssi->num_ports; i++) {
 283                        omap_port = omap_ssi->port[i];
 284
 285                        if (!omap_port)
 286                                continue;
 287
 288                        /* Workaround for SWBREAK + CAwake down race in CMT */
 289                        disable_irq(omap_port->wake_irq);
 290
 291                        /* stop all ssi communication */
 292                        pinctrl_pm_select_idle_state(omap_port->pdev);
 293                        udelay(1); /* wait for racing frames */
 294                }
 295
 296                break;
 297        case ABORT_RATE_CHANGE:
 298                dev_dbg(&ssi->device, "abort rate change\n");
 299                fallthrough;
 300        case POST_RATE_CHANGE:
 301                dev_dbg(&ssi->device, "post rate change (%lu -> %lu)\n",
 302                        clk_data->old_rate, clk_data->new_rate);
 303                omap_ssi->fck_rate = DIV_ROUND_CLOSEST(clk_data->new_rate, 1000); /* kHz */
 304
 305                for (i = 0; i < ssi->num_ports; i++) {
 306                        omap_port = omap_ssi->port[i];
 307
 308                        if (!omap_port)
 309                                continue;
 310
 311                        omap_ssi_port_update_fclk(ssi, omap_port);
 312
 313                        /* resume ssi communication */
 314                        pinctrl_pm_select_default_state(omap_port->pdev);
 315                        enable_irq(omap_port->wake_irq);
 316                }
 317
 318                break;
 319        default:
 320                break;
 321        }
 322
 323        return NOTIFY_DONE;
 324}
 325
 326static int ssi_get_iomem(struct platform_device *pd,
 327                const char *name, void __iomem **pbase, dma_addr_t *phy)
 328{
 329        struct resource *mem;
 330        void __iomem *base;
 331        struct hsi_controller *ssi = platform_get_drvdata(pd);
 332
 333        mem = platform_get_resource_byname(pd, IORESOURCE_MEM, name);
 334        base = devm_ioremap_resource(&ssi->device, mem);
 335        if (IS_ERR(base))
 336                return PTR_ERR(base);
 337
 338        *pbase = base;
 339
 340        if (phy)
 341                *phy = mem->start;
 342
 343        return 0;
 344}
 345
 346static int ssi_add_controller(struct hsi_controller *ssi,
 347                                                struct platform_device *pd)
 348{
 349        struct omap_ssi_controller *omap_ssi;
 350        int err;
 351
 352        omap_ssi = devm_kzalloc(&ssi->device, sizeof(*omap_ssi), GFP_KERNEL);
 353        if (!omap_ssi)
 354                return -ENOMEM;
 355
 356        err = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
 357        if (err < 0)
 358                return err;
 359        ssi->id = err;
 360
 361        ssi->owner = THIS_MODULE;
 362        ssi->device.parent = &pd->dev;
 363        dev_set_name(&ssi->device, "ssi%d", ssi->id);
 364        hsi_controller_set_drvdata(ssi, omap_ssi);
 365        omap_ssi->dev = &ssi->device;
 366        err = ssi_get_iomem(pd, "sys", &omap_ssi->sys, NULL);
 367        if (err < 0)
 368                goto out_err;
 369        err = ssi_get_iomem(pd, "gdd", &omap_ssi->gdd, NULL);
 370        if (err < 0)
 371                goto out_err;
 372        err = platform_get_irq_byname(pd, "gdd_mpu");
 373        if (err < 0)
 374                goto out_err;
 375        omap_ssi->gdd_irq = err;
 376        tasklet_init(&omap_ssi->gdd_tasklet, ssi_gdd_tasklet,
 377                                                        (unsigned long)ssi);
 378        err = devm_request_irq(&ssi->device, omap_ssi->gdd_irq, ssi_gdd_isr,
 379                                                0, "gdd_mpu", ssi);
 380        if (err < 0) {
 381                dev_err(&ssi->device, "Request GDD IRQ %d failed (%d)",
 382                                                        omap_ssi->gdd_irq, err);
 383                goto out_err;
 384        }
 385
 386        omap_ssi->port = devm_kcalloc(&ssi->device, ssi->num_ports,
 387                                      sizeof(*omap_ssi->port), GFP_KERNEL);
 388        if (!omap_ssi->port) {
 389                err = -ENOMEM;
 390                goto out_err;
 391        }
 392
 393        omap_ssi->fck = devm_clk_get(&ssi->device, "ssi_ssr_fck");
 394        if (IS_ERR(omap_ssi->fck)) {
 395                dev_err(&pd->dev, "Could not acquire clock \"ssi_ssr_fck\": %li\n",
 396                        PTR_ERR(omap_ssi->fck));
 397                err = -ENODEV;
 398                goto out_err;
 399        }
 400
 401        omap_ssi->fck_nb.notifier_call = ssi_clk_event;
 402        omap_ssi->fck_nb.priority = INT_MAX;
 403        clk_notifier_register(omap_ssi->fck, &omap_ssi->fck_nb);
 404
 405        /* TODO: find register, which can be used to detect context loss */
 406        omap_ssi->get_loss = NULL;
 407
 408        omap_ssi->max_speed = UINT_MAX;
 409        spin_lock_init(&omap_ssi->lock);
 410        err = hsi_register_controller(ssi);
 411
 412        if (err < 0)
 413                goto out_err;
 414
 415        return 0;
 416
 417out_err:
 418        ida_simple_remove(&platform_omap_ssi_ida, ssi->id);
 419        return err;
 420}
 421
 422static int ssi_hw_init(struct hsi_controller *ssi)
 423{
 424        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 425        int err;
 426
 427        err = pm_runtime_resume_and_get(ssi->device.parent);
 428        if (err < 0) {
 429                dev_err(&ssi->device, "runtime PM failed %d\n", err);
 430                return err;
 431        }
 432        /* Resetting GDD */
 433        writel_relaxed(SSI_SWRESET, omap_ssi->gdd + SSI_GDD_GRST_REG);
 434        /* Get FCK rate in kHz */
 435        omap_ssi->fck_rate = DIV_ROUND_CLOSEST(ssi_get_clk_rate(ssi), 1000);
 436        dev_dbg(&ssi->device, "SSI fck rate %lu kHz\n", omap_ssi->fck_rate);
 437
 438        writel_relaxed(SSI_CLK_AUTOGATING_ON, omap_ssi->sys + SSI_GDD_GCR_REG);
 439        omap_ssi->gdd_gcr = SSI_CLK_AUTOGATING_ON;
 440        pm_runtime_put_sync(ssi->device.parent);
 441
 442        return 0;
 443}
 444
 445static void ssi_remove_controller(struct hsi_controller *ssi)
 446{
 447        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 448        int id = ssi->id;
 449        tasklet_kill(&omap_ssi->gdd_tasklet);
 450        hsi_unregister_controller(ssi);
 451        clk_notifier_unregister(omap_ssi->fck, &omap_ssi->fck_nb);
 452        ida_simple_remove(&platform_omap_ssi_ida, id);
 453}
 454
 455static inline int ssi_of_get_available_ports_count(const struct device_node *np)
 456{
 457        struct device_node *child;
 458        int num = 0;
 459
 460        for_each_available_child_of_node(np, child)
 461                if (of_device_is_compatible(child, "ti,omap3-ssi-port"))
 462                        num++;
 463
 464        return num;
 465}
 466
 467static int ssi_remove_ports(struct device *dev, void *c)
 468{
 469        struct platform_device *pdev = to_platform_device(dev);
 470
 471        if (!dev->of_node)
 472                return 0;
 473
 474        of_node_clear_flag(dev->of_node, OF_POPULATED);
 475        of_device_unregister(pdev);
 476
 477        return 0;
 478}
 479
 480static int ssi_probe(struct platform_device *pd)
 481{
 482        struct platform_device *childpdev;
 483        struct device_node *np = pd->dev.of_node;
 484        struct device_node *child;
 485        struct hsi_controller *ssi;
 486        int err;
 487        int num_ports;
 488
 489        if (!np) {
 490                dev_err(&pd->dev, "missing device tree data\n");
 491                return -EINVAL;
 492        }
 493
 494        num_ports = ssi_of_get_available_ports_count(np);
 495
 496        ssi = hsi_alloc_controller(num_ports, GFP_KERNEL);
 497        if (!ssi) {
 498                dev_err(&pd->dev, "No memory for controller\n");
 499                return -ENOMEM;
 500        }
 501
 502        platform_set_drvdata(pd, ssi);
 503
 504        err = ssi_add_controller(ssi, pd);
 505        if (err < 0)
 506                goto out1;
 507
 508        pm_runtime_enable(&pd->dev);
 509
 510        err = ssi_hw_init(ssi);
 511        if (err < 0)
 512                goto out2;
 513#ifdef CONFIG_DEBUG_FS
 514        err = ssi_debug_add_ctrl(ssi);
 515        if (err < 0)
 516                goto out2;
 517#endif
 518
 519        for_each_available_child_of_node(np, child) {
 520                if (!of_device_is_compatible(child, "ti,omap3-ssi-port"))
 521                        continue;
 522
 523                childpdev = of_platform_device_create(child, NULL, &pd->dev);
 524                if (!childpdev) {
 525                        err = -ENODEV;
 526                        dev_err(&pd->dev, "failed to create ssi controller port\n");
 527                        goto out3;
 528                }
 529        }
 530
 531        dev_info(&pd->dev, "ssi controller %d initialized (%d ports)!\n",
 532                ssi->id, num_ports);
 533        return err;
 534out3:
 535        device_for_each_child(&pd->dev, NULL, ssi_remove_ports);
 536out2:
 537        ssi_remove_controller(ssi);
 538out1:
 539        platform_set_drvdata(pd, NULL);
 540        pm_runtime_disable(&pd->dev);
 541
 542        return err;
 543}
 544
 545static int ssi_remove(struct platform_device *pd)
 546{
 547        struct hsi_controller *ssi = platform_get_drvdata(pd);
 548
 549        /* cleanup of of_platform_populate() call */
 550        device_for_each_child(&pd->dev, NULL, ssi_remove_ports);
 551
 552#ifdef CONFIG_DEBUG_FS
 553        ssi_debug_remove_ctrl(ssi);
 554#endif
 555        ssi_remove_controller(ssi);
 556        platform_set_drvdata(pd, NULL);
 557
 558        pm_runtime_disable(&pd->dev);
 559
 560        return 0;
 561}
 562
 563#ifdef CONFIG_PM
 564static int omap_ssi_runtime_suspend(struct device *dev)
 565{
 566        struct hsi_controller *ssi = dev_get_drvdata(dev);
 567        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 568
 569        dev_dbg(dev, "runtime suspend!\n");
 570
 571        if (omap_ssi->get_loss)
 572                omap_ssi->loss_count =
 573                                omap_ssi->get_loss(ssi->device.parent);
 574
 575        return 0;
 576}
 577
 578static int omap_ssi_runtime_resume(struct device *dev)
 579{
 580        struct hsi_controller *ssi = dev_get_drvdata(dev);
 581        struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 582
 583        dev_dbg(dev, "runtime resume!\n");
 584
 585        if ((omap_ssi->get_loss) && (omap_ssi->loss_count ==
 586                                omap_ssi->get_loss(ssi->device.parent)))
 587                return 0;
 588
 589        writel_relaxed(omap_ssi->gdd_gcr, omap_ssi->gdd + SSI_GDD_GCR_REG);
 590
 591        return 0;
 592}
 593
 594static const struct dev_pm_ops omap_ssi_pm_ops = {
 595        SET_RUNTIME_PM_OPS(omap_ssi_runtime_suspend, omap_ssi_runtime_resume,
 596                NULL)
 597};
 598
 599#define DEV_PM_OPS     (&omap_ssi_pm_ops)
 600#else
 601#define DEV_PM_OPS     NULL
 602#endif
 603
 604#ifdef CONFIG_OF
 605static const struct of_device_id omap_ssi_of_match[] = {
 606        { .compatible = "ti,omap3-ssi", },
 607        {},
 608};
 609MODULE_DEVICE_TABLE(of, omap_ssi_of_match);
 610#else
 611#define omap_ssi_of_match NULL
 612#endif
 613
 614static struct platform_driver ssi_pdriver = {
 615        .probe = ssi_probe,
 616        .remove = ssi_remove,
 617        .driver = {
 618                .name   = "omap_ssi",
 619                .pm     = DEV_PM_OPS,
 620                .of_match_table = omap_ssi_of_match,
 621        },
 622};
 623
 624static int __init ssi_init(void) {
 625        int ret;
 626
 627        ret = platform_driver_register(&ssi_pdriver);
 628        if (ret)
 629                return ret;
 630
 631        return platform_driver_register(&ssi_port_pdriver);
 632}
 633module_init(ssi_init);
 634
 635static void __exit ssi_exit(void) {
 636        platform_driver_unregister(&ssi_port_pdriver);
 637        platform_driver_unregister(&ssi_pdriver);
 638}
 639module_exit(ssi_exit);
 640
 641MODULE_ALIAS("platform:omap_ssi");
 642MODULE_AUTHOR("Carlos Chinea <carlos.chinea@nokia.com>");
 643MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
 644MODULE_DESCRIPTION("Synchronous Serial Interface Driver");
 645MODULE_LICENSE("GPL v2");
 646