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