cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

omap_ssi_core.c (17077B)


      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");