Path: blob/master/drivers/hsi/controllers/omap_ssi_port.c
29266 views
// SPDX-License-Identifier: GPL-2.0-only1/* OMAP SSI port driver.2*3* Copyright (C) 2010 Nokia Corporation. All rights reserved.4* Copyright (C) 2014 Sebastian Reichel <[email protected]>5*6* Contact: Carlos Chinea <[email protected]>7*/89#include <linux/mod_devicetable.h>10#include <linux/platform_device.h>11#include <linux/dma-mapping.h>12#include <linux/pm_runtime.h>13#include <linux/delay.h>1415#include <linux/gpio/consumer.h>16#include <linux/pinctrl/consumer.h>17#include <linux/debugfs.h>1819#include "omap_ssi_regs.h"20#include "omap_ssi.h"2122static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused)23{24return 0;25}2627static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused)28{29return 0;30}3132static inline unsigned int ssi_wakein(struct hsi_port *port)33{34struct omap_ssi_port *omap_port = hsi_port_drvdata(port);35return gpiod_get_value(omap_port->wake_gpio);36}3738#ifdef CONFIG_DEBUG_FS39static void ssi_debug_remove_port(struct hsi_port *port)40{41struct omap_ssi_port *omap_port = hsi_port_drvdata(port);4243debugfs_remove_recursive(omap_port->dir);44}4546static int ssi_port_regs_show(struct seq_file *m, void *p __maybe_unused)47{48struct hsi_port *port = m->private;49struct omap_ssi_port *omap_port = hsi_port_drvdata(port);50struct hsi_controller *ssi = to_hsi_controller(port->device.parent);51struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);52void __iomem *base = omap_ssi->sys;53unsigned int ch;5455pm_runtime_get_sync(omap_port->pdev);56if (omap_port->wake_irq > 0)57seq_printf(m, "CAWAKE\t\t: %d\n", ssi_wakein(port));58seq_printf(m, "WAKE\t\t: 0x%08x\n",59readl(base + SSI_WAKE_REG(port->num)));60seq_printf(m, "MPU_ENABLE_IRQ%d\t: 0x%08x\n", 0,61readl(base + SSI_MPU_ENABLE_REG(port->num, 0)));62seq_printf(m, "MPU_STATUS_IRQ%d\t: 0x%08x\n", 0,63readl(base + SSI_MPU_STATUS_REG(port->num, 0)));64/* SST */65base = omap_port->sst_base;66seq_puts(m, "\nSST\n===\n");67seq_printf(m, "ID SST\t\t: 0x%08x\n",68readl(base + SSI_SST_ID_REG));69seq_printf(m, "MODE\t\t: 0x%08x\n",70readl(base + SSI_SST_MODE_REG));71seq_printf(m, "FRAMESIZE\t: 0x%08x\n",72readl(base + SSI_SST_FRAMESIZE_REG));73seq_printf(m, "DIVISOR\t\t: 0x%08x\n",74readl(base + SSI_SST_DIVISOR_REG));75seq_printf(m, "CHANNELS\t: 0x%08x\n",76readl(base + SSI_SST_CHANNELS_REG));77seq_printf(m, "ARBMODE\t\t: 0x%08x\n",78readl(base + SSI_SST_ARBMODE_REG));79seq_printf(m, "TXSTATE\t\t: 0x%08x\n",80readl(base + SSI_SST_TXSTATE_REG));81seq_printf(m, "BUFSTATE\t: 0x%08x\n",82readl(base + SSI_SST_BUFSTATE_REG));83seq_printf(m, "BREAK\t\t: 0x%08x\n",84readl(base + SSI_SST_BREAK_REG));85for (ch = 0; ch < omap_port->channels; ch++) {86seq_printf(m, "BUFFER_CH%d\t: 0x%08x\n", ch,87readl(base + SSI_SST_BUFFER_CH_REG(ch)));88}89/* SSR */90base = omap_port->ssr_base;91seq_puts(m, "\nSSR\n===\n");92seq_printf(m, "ID SSR\t\t: 0x%08x\n",93readl(base + SSI_SSR_ID_REG));94seq_printf(m, "MODE\t\t: 0x%08x\n",95readl(base + SSI_SSR_MODE_REG));96seq_printf(m, "FRAMESIZE\t: 0x%08x\n",97readl(base + SSI_SSR_FRAMESIZE_REG));98seq_printf(m, "CHANNELS\t: 0x%08x\n",99readl(base + SSI_SSR_CHANNELS_REG));100seq_printf(m, "TIMEOUT\t\t: 0x%08x\n",101readl(base + SSI_SSR_TIMEOUT_REG));102seq_printf(m, "RXSTATE\t\t: 0x%08x\n",103readl(base + SSI_SSR_RXSTATE_REG));104seq_printf(m, "BUFSTATE\t: 0x%08x\n",105readl(base + SSI_SSR_BUFSTATE_REG));106seq_printf(m, "BREAK\t\t: 0x%08x\n",107readl(base + SSI_SSR_BREAK_REG));108seq_printf(m, "ERROR\t\t: 0x%08x\n",109readl(base + SSI_SSR_ERROR_REG));110seq_printf(m, "ERRORACK\t: 0x%08x\n",111readl(base + SSI_SSR_ERRORACK_REG));112for (ch = 0; ch < omap_port->channels; ch++) {113seq_printf(m, "BUFFER_CH%d\t: 0x%08x\n", ch,114readl(base + SSI_SSR_BUFFER_CH_REG(ch)));115}116pm_runtime_put_autosuspend(omap_port->pdev);117118return 0;119}120121DEFINE_SHOW_ATTRIBUTE(ssi_port_regs);122123static int ssi_div_get(void *data, u64 *val)124{125struct hsi_port *port = data;126struct omap_ssi_port *omap_port = hsi_port_drvdata(port);127128pm_runtime_get_sync(omap_port->pdev);129*val = readl(omap_port->sst_base + SSI_SST_DIVISOR_REG);130pm_runtime_put_autosuspend(omap_port->pdev);131132return 0;133}134135static int ssi_div_set(void *data, u64 val)136{137struct hsi_port *port = data;138struct omap_ssi_port *omap_port = hsi_port_drvdata(port);139140if (val > 127)141return -EINVAL;142143pm_runtime_get_sync(omap_port->pdev);144writel(val, omap_port->sst_base + SSI_SST_DIVISOR_REG);145omap_port->sst.divisor = val;146pm_runtime_put_autosuspend(omap_port->pdev);147148return 0;149}150151DEFINE_DEBUGFS_ATTRIBUTE(ssi_sst_div_fops, ssi_div_get, ssi_div_set, "%llu\n");152153static void ssi_debug_add_port(struct omap_ssi_port *omap_port,154struct dentry *dir)155{156struct hsi_port *port = to_hsi_port(omap_port->dev);157158dir = debugfs_create_dir(dev_name(omap_port->dev), dir);159omap_port->dir = dir;160debugfs_create_file("regs", S_IRUGO, dir, port, &ssi_port_regs_fops);161dir = debugfs_create_dir("sst", dir);162debugfs_create_file_unsafe("divisor", 0644, dir, port,163&ssi_sst_div_fops);164}165#endif166167static void ssi_process_errqueue(struct work_struct *work)168{169struct omap_ssi_port *omap_port;170struct list_head *head, *tmp;171struct hsi_msg *msg;172173omap_port = container_of(work, struct omap_ssi_port, errqueue_work.work);174175list_for_each_safe(head, tmp, &omap_port->errqueue) {176msg = list_entry(head, struct hsi_msg, link);177msg->complete(msg);178list_del(head);179}180}181182static int ssi_claim_lch(struct hsi_msg *msg)183{184185struct hsi_port *port = hsi_get_port(msg->cl);186struct hsi_controller *ssi = to_hsi_controller(port->device.parent);187struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);188int lch;189190for (lch = 0; lch < SSI_MAX_GDD_LCH; lch++)191if (!omap_ssi->gdd_trn[lch].msg) {192omap_ssi->gdd_trn[lch].msg = msg;193omap_ssi->gdd_trn[lch].sg = msg->sgt.sgl;194return lch;195}196197return -EBUSY;198}199200static int ssi_start_dma(struct hsi_msg *msg, int lch)201{202struct hsi_port *port = hsi_get_port(msg->cl);203struct omap_ssi_port *omap_port = hsi_port_drvdata(port);204struct hsi_controller *ssi = to_hsi_controller(port->device.parent);205struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);206void __iomem *gdd = omap_ssi->gdd;207int err;208u16 csdp;209u16 ccr;210u32 s_addr;211u32 d_addr;212u32 tmp;213214/* Hold clocks during the transfer */215pm_runtime_get(omap_port->pdev);216217if (!pm_runtime_active(omap_port->pdev)) {218dev_warn(&port->device, "ssi_start_dma called without runtime PM!\n");219pm_runtime_put_autosuspend(omap_port->pdev);220return -EREMOTEIO;221}222223if (msg->ttype == HSI_MSG_READ) {224err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,225DMA_FROM_DEVICE);226if (!err) {227dev_dbg(&ssi->device, "DMA map SG failed !\n");228pm_runtime_put_autosuspend(omap_port->pdev);229return -EIO;230}231csdp = SSI_DST_BURST_4x32_BIT | SSI_DST_MEMORY_PORT |232SSI_SRC_SINGLE_ACCESS0 | SSI_SRC_PERIPHERAL_PORT |233SSI_DATA_TYPE_S32;234ccr = msg->channel + 0x10 + (port->num * 8); /* Sync */235ccr |= SSI_DST_AMODE_POSTINC | SSI_SRC_AMODE_CONST |236SSI_CCR_ENABLE;237s_addr = omap_port->ssr_dma +238SSI_SSR_BUFFER_CH_REG(msg->channel);239d_addr = sg_dma_address(msg->sgt.sgl);240} else {241err = dma_map_sg(&ssi->device, msg->sgt.sgl, msg->sgt.nents,242DMA_TO_DEVICE);243if (!err) {244dev_dbg(&ssi->device, "DMA map SG failed !\n");245pm_runtime_put_autosuspend(omap_port->pdev);246return -EIO;247}248csdp = SSI_SRC_BURST_4x32_BIT | SSI_SRC_MEMORY_PORT |249SSI_DST_SINGLE_ACCESS0 | SSI_DST_PERIPHERAL_PORT |250SSI_DATA_TYPE_S32;251ccr = (msg->channel + 1 + (port->num * 8)) & 0xf; /* Sync */252ccr |= SSI_SRC_AMODE_POSTINC | SSI_DST_AMODE_CONST |253SSI_CCR_ENABLE;254s_addr = sg_dma_address(msg->sgt.sgl);255d_addr = omap_port->sst_dma +256SSI_SST_BUFFER_CH_REG(msg->channel);257}258dev_dbg(&ssi->device, "lch %d cdsp %08x ccr %04x s_addr %08x d_addr %08x\n",259lch, csdp, ccr, s_addr, d_addr);260261writew_relaxed(csdp, gdd + SSI_GDD_CSDP_REG(lch));262writew_relaxed(SSI_BLOCK_IE | SSI_TOUT_IE, gdd + SSI_GDD_CICR_REG(lch));263writel_relaxed(d_addr, gdd + SSI_GDD_CDSA_REG(lch));264writel_relaxed(s_addr, gdd + SSI_GDD_CSSA_REG(lch));265writew_relaxed(SSI_BYTES_TO_FRAMES(msg->sgt.sgl->length),266gdd + SSI_GDD_CEN_REG(lch));267268spin_lock_bh(&omap_ssi->lock);269tmp = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);270tmp |= SSI_GDD_LCH(lch);271writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);272spin_unlock_bh(&omap_ssi->lock);273writew(ccr, gdd + SSI_GDD_CCR_REG(lch));274msg->status = HSI_STATUS_PROCEEDING;275276return 0;277}278279static int ssi_start_pio(struct hsi_msg *msg)280{281struct hsi_port *port = hsi_get_port(msg->cl);282struct omap_ssi_port *omap_port = hsi_port_drvdata(port);283struct hsi_controller *ssi = to_hsi_controller(port->device.parent);284struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);285u32 val;286287pm_runtime_get(omap_port->pdev);288289if (!pm_runtime_active(omap_port->pdev)) {290dev_warn(&port->device, "ssi_start_pio called without runtime PM!\n");291pm_runtime_put_autosuspend(omap_port->pdev);292return -EREMOTEIO;293}294295if (msg->ttype == HSI_MSG_WRITE) {296val = SSI_DATAACCEPT(msg->channel);297/* Hold clocks for pio writes */298pm_runtime_get(omap_port->pdev);299} else {300val = SSI_DATAAVAILABLE(msg->channel) | SSI_ERROROCCURED;301}302dev_dbg(&port->device, "Single %s transfer\n",303msg->ttype ? "write" : "read");304val |= readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));305writel(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));306pm_runtime_put_autosuspend(omap_port->pdev);307msg->actual_len = 0;308msg->status = HSI_STATUS_PROCEEDING;309310return 0;311}312313static int ssi_start_transfer(struct list_head *queue)314{315struct hsi_msg *msg;316int lch = -1;317318if (list_empty(queue))319return 0;320msg = list_first_entry(queue, struct hsi_msg, link);321if (msg->status != HSI_STATUS_QUEUED)322return 0;323if ((msg->sgt.nents) && (msg->sgt.sgl->length > sizeof(u32)))324lch = ssi_claim_lch(msg);325if (lch >= 0)326return ssi_start_dma(msg, lch);327else328return ssi_start_pio(msg);329}330331static int ssi_async_break(struct hsi_msg *msg)332{333struct hsi_port *port = hsi_get_port(msg->cl);334struct omap_ssi_port *omap_port = hsi_port_drvdata(port);335struct hsi_controller *ssi = to_hsi_controller(port->device.parent);336struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);337int err = 0;338u32 tmp;339340pm_runtime_get_sync(omap_port->pdev);341if (msg->ttype == HSI_MSG_WRITE) {342if (omap_port->sst.mode != SSI_MODE_FRAME) {343err = -EINVAL;344goto out;345}346writel(1, omap_port->sst_base + SSI_SST_BREAK_REG);347msg->status = HSI_STATUS_COMPLETED;348msg->complete(msg);349} else {350if (omap_port->ssr.mode != SSI_MODE_FRAME) {351err = -EINVAL;352goto out;353}354spin_lock_bh(&omap_port->lock);355tmp = readl(omap_ssi->sys +356SSI_MPU_ENABLE_REG(port->num, 0));357writel(tmp | SSI_BREAKDETECTED,358omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));359msg->status = HSI_STATUS_PROCEEDING;360list_add_tail(&msg->link, &omap_port->brkqueue);361spin_unlock_bh(&omap_port->lock);362}363out:364pm_runtime_put_autosuspend(omap_port->pdev);365366return err;367}368369static int ssi_async(struct hsi_msg *msg)370{371struct hsi_port *port = hsi_get_port(msg->cl);372struct omap_ssi_port *omap_port = hsi_port_drvdata(port);373struct list_head *queue;374int err = 0;375376BUG_ON(!msg);377378if (msg->sgt.nents > 1)379return -ENOSYS; /* TODO: Add sg support */380381if (msg->break_frame)382return ssi_async_break(msg);383384if (msg->ttype) {385BUG_ON(msg->channel >= omap_port->sst.channels);386queue = &omap_port->txqueue[msg->channel];387} else {388BUG_ON(msg->channel >= omap_port->ssr.channels);389queue = &omap_port->rxqueue[msg->channel];390}391msg->status = HSI_STATUS_QUEUED;392393pm_runtime_get_sync(omap_port->pdev);394spin_lock_bh(&omap_port->lock);395list_add_tail(&msg->link, queue);396err = ssi_start_transfer(queue);397if (err < 0) {398list_del(&msg->link);399msg->status = HSI_STATUS_ERROR;400}401spin_unlock_bh(&omap_port->lock);402pm_runtime_put_autosuspend(omap_port->pdev);403dev_dbg(&port->device, "msg status %d ttype %d ch %d\n",404msg->status, msg->ttype, msg->channel);405406return err;407}408409static u32 ssi_calculate_div(struct hsi_controller *ssi)410{411struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);412u32 tx_fckrate = (u32) omap_ssi->fck_rate;413414/* / 2 : SSI TX clock is always half of the SSI functional clock */415tx_fckrate >>= 1;416/* Round down when tx_fckrate % omap_ssi->max_speed == 0 */417tx_fckrate--;418dev_dbg(&ssi->device, "TX div %d for fck_rate %lu Khz speed %d Kb/s\n",419tx_fckrate / omap_ssi->max_speed, omap_ssi->fck_rate,420omap_ssi->max_speed);421422return tx_fckrate / omap_ssi->max_speed;423}424425static void ssi_flush_queue(struct list_head *queue, struct hsi_client *cl)426{427struct list_head *node, *tmp;428struct hsi_msg *msg;429430list_for_each_safe(node, tmp, queue) {431msg = list_entry(node, struct hsi_msg, link);432if ((cl) && (cl != msg->cl))433continue;434list_del(node);435pr_debug("flush queue: ch %d, msg %p len %d type %d ctxt %p\n",436msg->channel, msg, msg->sgt.sgl->length,437msg->ttype, msg->context);438if (msg->destructor)439msg->destructor(msg);440else441hsi_free_msg(msg);442}443}444445static int ssi_setup(struct hsi_client *cl)446{447struct hsi_port *port = to_hsi_port(cl->device.parent);448struct omap_ssi_port *omap_port = hsi_port_drvdata(port);449struct hsi_controller *ssi = to_hsi_controller(port->device.parent);450struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);451void __iomem *sst = omap_port->sst_base;452void __iomem *ssr = omap_port->ssr_base;453u32 div;454u32 val;455int err = 0;456457pm_runtime_get_sync(omap_port->pdev);458spin_lock_bh(&omap_port->lock);459if (cl->tx_cfg.speed)460omap_ssi->max_speed = cl->tx_cfg.speed;461div = ssi_calculate_div(ssi);462if (div > SSI_MAX_DIVISOR) {463dev_err(&cl->device, "Invalid TX speed %d Mb/s (div %d)\n",464cl->tx_cfg.speed, div);465err = -EINVAL;466goto out;467}468/* Set TX/RX module to sleep to stop TX/RX during cfg update */469writel_relaxed(SSI_MODE_SLEEP, sst + SSI_SST_MODE_REG);470writel_relaxed(SSI_MODE_SLEEP, ssr + SSI_SSR_MODE_REG);471/* Flush posted write */472val = readl(ssr + SSI_SSR_MODE_REG);473/* TX */474writel_relaxed(31, sst + SSI_SST_FRAMESIZE_REG);475writel_relaxed(div, sst + SSI_SST_DIVISOR_REG);476writel_relaxed(cl->tx_cfg.num_hw_channels, sst + SSI_SST_CHANNELS_REG);477writel_relaxed(cl->tx_cfg.arb_mode, sst + SSI_SST_ARBMODE_REG);478writel_relaxed(cl->tx_cfg.mode, sst + SSI_SST_MODE_REG);479/* RX */480writel_relaxed(31, ssr + SSI_SSR_FRAMESIZE_REG);481writel_relaxed(cl->rx_cfg.num_hw_channels, ssr + SSI_SSR_CHANNELS_REG);482writel_relaxed(0, ssr + SSI_SSR_TIMEOUT_REG);483/* Cleanup the break queue if we leave FRAME mode */484if ((omap_port->ssr.mode == SSI_MODE_FRAME) &&485(cl->rx_cfg.mode != SSI_MODE_FRAME))486ssi_flush_queue(&omap_port->brkqueue, cl);487writel_relaxed(cl->rx_cfg.mode, ssr + SSI_SSR_MODE_REG);488omap_port->channels = max(cl->rx_cfg.num_hw_channels,489cl->tx_cfg.num_hw_channels);490/* Shadow registering for OFF mode */491/* SST */492omap_port->sst.divisor = div;493omap_port->sst.frame_size = 31;494omap_port->sst.channels = cl->tx_cfg.num_hw_channels;495omap_port->sst.arb_mode = cl->tx_cfg.arb_mode;496omap_port->sst.mode = cl->tx_cfg.mode;497/* SSR */498omap_port->ssr.frame_size = 31;499omap_port->ssr.timeout = 0;500omap_port->ssr.channels = cl->rx_cfg.num_hw_channels;501omap_port->ssr.mode = cl->rx_cfg.mode;502out:503spin_unlock_bh(&omap_port->lock);504pm_runtime_put_autosuspend(omap_port->pdev);505506return err;507}508509static int ssi_flush(struct hsi_client *cl)510{511struct hsi_port *port = hsi_get_port(cl);512struct omap_ssi_port *omap_port = hsi_port_drvdata(port);513struct hsi_controller *ssi = to_hsi_controller(port->device.parent);514struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);515struct hsi_msg *msg;516void __iomem *sst = omap_port->sst_base;517void __iomem *ssr = omap_port->ssr_base;518unsigned int i;519u32 err;520521pm_runtime_get_sync(omap_port->pdev);522spin_lock_bh(&omap_port->lock);523524/* stop all ssi communication */525pinctrl_pm_select_idle_state(omap_port->pdev);526udelay(1); /* wait for racing frames */527528/* Stop all DMA transfers */529for (i = 0; i < SSI_MAX_GDD_LCH; i++) {530msg = omap_ssi->gdd_trn[i].msg;531if (!msg || (port != hsi_get_port(msg->cl)))532continue;533writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));534if (msg->ttype == HSI_MSG_READ)535pm_runtime_put_autosuspend(omap_port->pdev);536omap_ssi->gdd_trn[i].msg = NULL;537}538/* Flush all SST buffers */539writel_relaxed(0, sst + SSI_SST_BUFSTATE_REG);540writel_relaxed(0, sst + SSI_SST_TXSTATE_REG);541/* Flush all SSR buffers */542writel_relaxed(0, ssr + SSI_SSR_RXSTATE_REG);543writel_relaxed(0, ssr + SSI_SSR_BUFSTATE_REG);544/* Flush all errors */545err = readl(ssr + SSI_SSR_ERROR_REG);546writel_relaxed(err, ssr + SSI_SSR_ERRORACK_REG);547/* Flush break */548writel_relaxed(0, ssr + SSI_SSR_BREAK_REG);549/* Clear interrupts */550writel_relaxed(0, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));551writel_relaxed(0xffffff00,552omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));553writel_relaxed(0, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);554writel(0xff, omap_ssi->sys + SSI_GDD_MPU_IRQ_STATUS_REG);555/* Dequeue all pending requests */556for (i = 0; i < omap_port->channels; i++) {557/* Release write clocks */558if (!list_empty(&omap_port->txqueue[i]))559pm_runtime_put_autosuspend(omap_port->pdev);560ssi_flush_queue(&omap_port->txqueue[i], NULL);561ssi_flush_queue(&omap_port->rxqueue[i], NULL);562}563ssi_flush_queue(&omap_port->brkqueue, NULL);564565/* Resume SSI communication */566pinctrl_pm_select_default_state(omap_port->pdev);567568spin_unlock_bh(&omap_port->lock);569pm_runtime_put_autosuspend(omap_port->pdev);570571return 0;572}573574static void start_tx_work(struct work_struct *work)575{576struct omap_ssi_port *omap_port =577container_of(work, struct omap_ssi_port, work);578struct hsi_port *port = to_hsi_port(omap_port->dev);579struct hsi_controller *ssi = to_hsi_controller(port->device.parent);580struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);581582pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */583writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));584}585586static int ssi_start_tx(struct hsi_client *cl)587{588struct hsi_port *port = hsi_get_port(cl);589struct omap_ssi_port *omap_port = hsi_port_drvdata(port);590591dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount);592593spin_lock_bh(&omap_port->wk_lock);594if (omap_port->wk_refcount++) {595spin_unlock_bh(&omap_port->wk_lock);596return 0;597}598spin_unlock_bh(&omap_port->wk_lock);599600schedule_work(&omap_port->work);601602return 0;603}604605static int ssi_stop_tx(struct hsi_client *cl)606{607struct hsi_port *port = hsi_get_port(cl);608struct omap_ssi_port *omap_port = hsi_port_drvdata(port);609struct hsi_controller *ssi = to_hsi_controller(port->device.parent);610struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);611612dev_dbg(&port->device, "Wake out low %d\n", omap_port->wk_refcount);613614spin_lock_bh(&omap_port->wk_lock);615BUG_ON(!omap_port->wk_refcount);616if (--omap_port->wk_refcount) {617spin_unlock_bh(&omap_port->wk_lock);618return 0;619}620writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));621spin_unlock_bh(&omap_port->wk_lock);622623pm_runtime_put_autosuspend(omap_port->pdev); /* Release clocks */624625626return 0;627}628629static void ssi_transfer(struct omap_ssi_port *omap_port,630struct list_head *queue)631{632struct hsi_msg *msg;633int err = -1;634635pm_runtime_get(omap_port->pdev);636spin_lock_bh(&omap_port->lock);637while (err < 0) {638err = ssi_start_transfer(queue);639if (err < 0) {640msg = list_first_entry(queue, struct hsi_msg, link);641msg->status = HSI_STATUS_ERROR;642msg->actual_len = 0;643list_del(&msg->link);644spin_unlock_bh(&omap_port->lock);645msg->complete(msg);646spin_lock_bh(&omap_port->lock);647}648}649spin_unlock_bh(&omap_port->lock);650pm_runtime_put_autosuspend(omap_port->pdev);651}652653static void ssi_cleanup_queues(struct hsi_client *cl)654{655struct hsi_port *port = hsi_get_port(cl);656struct omap_ssi_port *omap_port = hsi_port_drvdata(port);657struct hsi_controller *ssi = to_hsi_controller(port->device.parent);658struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);659struct hsi_msg *msg;660unsigned int i;661u32 rxbufstate = 0;662u32 txbufstate = 0;663u32 status = SSI_ERROROCCURED;664u32 tmp;665666ssi_flush_queue(&omap_port->brkqueue, cl);667if (list_empty(&omap_port->brkqueue))668status |= SSI_BREAKDETECTED;669670for (i = 0; i < omap_port->channels; i++) {671if (list_empty(&omap_port->txqueue[i]))672continue;673msg = list_first_entry(&omap_port->txqueue[i], struct hsi_msg,674link);675if ((msg->cl == cl) && (msg->status == HSI_STATUS_PROCEEDING)) {676txbufstate |= (1 << i);677status |= SSI_DATAACCEPT(i);678/* Release the clocks writes, also GDD ones */679pm_runtime_put_autosuspend(omap_port->pdev);680}681ssi_flush_queue(&omap_port->txqueue[i], cl);682}683for (i = 0; i < omap_port->channels; i++) {684if (list_empty(&omap_port->rxqueue[i]))685continue;686msg = list_first_entry(&omap_port->rxqueue[i], struct hsi_msg,687link);688if ((msg->cl == cl) && (msg->status == HSI_STATUS_PROCEEDING)) {689rxbufstate |= (1 << i);690status |= SSI_DATAAVAILABLE(i);691}692ssi_flush_queue(&omap_port->rxqueue[i], cl);693/* Check if we keep the error detection interrupt armed */694if (!list_empty(&omap_port->rxqueue[i]))695status &= ~SSI_ERROROCCURED;696}697/* Cleanup write buffers */698tmp = readl(omap_port->sst_base + SSI_SST_BUFSTATE_REG);699tmp &= ~txbufstate;700writel_relaxed(tmp, omap_port->sst_base + SSI_SST_BUFSTATE_REG);701/* Cleanup read buffers */702tmp = readl(omap_port->ssr_base + SSI_SSR_BUFSTATE_REG);703tmp &= ~rxbufstate;704writel_relaxed(tmp, omap_port->ssr_base + SSI_SSR_BUFSTATE_REG);705/* Disarm and ack pending interrupts */706tmp = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));707tmp &= ~status;708writel_relaxed(tmp, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));709writel_relaxed(status, omap_ssi->sys +710SSI_MPU_STATUS_REG(port->num, 0));711}712713static void ssi_cleanup_gdd(struct hsi_controller *ssi, struct hsi_client *cl)714{715struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);716struct hsi_port *port = hsi_get_port(cl);717struct omap_ssi_port *omap_port = hsi_port_drvdata(port);718struct hsi_msg *msg;719unsigned int i;720u32 val = 0;721u32 tmp;722723for (i = 0; i < SSI_MAX_GDD_LCH; i++) {724msg = omap_ssi->gdd_trn[i].msg;725if ((!msg) || (msg->cl != cl))726continue;727writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));728val |= (1 << i);729/*730* Clock references for write will be handled in731* ssi_cleanup_queues732*/733if (msg->ttype == HSI_MSG_READ) {734pm_runtime_put_autosuspend(omap_port->pdev);735}736omap_ssi->gdd_trn[i].msg = NULL;737}738tmp = readl_relaxed(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);739tmp &= ~val;740writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);741writel(val, omap_ssi->sys + SSI_GDD_MPU_IRQ_STATUS_REG);742}743744static int ssi_set_port_mode(struct omap_ssi_port *omap_port, u32 mode)745{746writel(mode, omap_port->sst_base + SSI_SST_MODE_REG);747writel(mode, omap_port->ssr_base + SSI_SSR_MODE_REG);748/* OCP barrier */749mode = readl(omap_port->ssr_base + SSI_SSR_MODE_REG);750751return 0;752}753754static int ssi_release(struct hsi_client *cl)755{756struct hsi_port *port = hsi_get_port(cl);757struct omap_ssi_port *omap_port = hsi_port_drvdata(port);758struct hsi_controller *ssi = to_hsi_controller(port->device.parent);759760pm_runtime_get_sync(omap_port->pdev);761spin_lock_bh(&omap_port->lock);762/* Stop all the pending DMA requests for that client */763ssi_cleanup_gdd(ssi, cl);764/* Now cleanup all the queues */765ssi_cleanup_queues(cl);766/* If it is the last client of the port, do extra checks and cleanup */767if (port->claimed <= 1) {768/*769* Drop the clock reference for the incoming wake line770* if it is still kept high by the other side.771*/772if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags))773pm_runtime_put_sync(omap_port->pdev);774pm_runtime_get(omap_port->pdev);775/* Stop any SSI TX/RX without a client */776ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);777omap_port->sst.mode = SSI_MODE_SLEEP;778omap_port->ssr.mode = SSI_MODE_SLEEP;779pm_runtime_put(omap_port->pdev);780WARN_ON(omap_port->wk_refcount != 0);781}782spin_unlock_bh(&omap_port->lock);783pm_runtime_put_sync(omap_port->pdev);784785return 0;786}787788789790static void ssi_error(struct hsi_port *port)791{792struct omap_ssi_port *omap_port = hsi_port_drvdata(port);793struct hsi_controller *ssi = to_hsi_controller(port->device.parent);794struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);795struct hsi_msg *msg;796unsigned int i;797u32 err;798u32 val;799u32 tmp;800801/* ACK error */802err = readl(omap_port->ssr_base + SSI_SSR_ERROR_REG);803dev_err(&port->device, "SSI error: 0x%02x\n", err);804if (!err) {805dev_dbg(&port->device, "spurious SSI error ignored!\n");806return;807}808spin_lock(&omap_ssi->lock);809/* Cancel all GDD read transfers */810for (i = 0, val = 0; i < SSI_MAX_GDD_LCH; i++) {811msg = omap_ssi->gdd_trn[i].msg;812if ((msg) && (msg->ttype == HSI_MSG_READ)) {813writew_relaxed(0, omap_ssi->gdd + SSI_GDD_CCR_REG(i));814val |= (1 << i);815omap_ssi->gdd_trn[i].msg = NULL;816}817}818tmp = readl(omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);819tmp &= ~val;820writel_relaxed(tmp, omap_ssi->sys + SSI_GDD_MPU_IRQ_ENABLE_REG);821spin_unlock(&omap_ssi->lock);822/* Cancel all PIO read transfers */823spin_lock(&omap_port->lock);824tmp = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));825tmp &= 0xfeff00ff; /* Disable error & all dataavailable interrupts */826writel_relaxed(tmp, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));827/* ACK error */828writel_relaxed(err, omap_port->ssr_base + SSI_SSR_ERRORACK_REG);829writel_relaxed(SSI_ERROROCCURED,830omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));831/* Signal the error all current pending read requests */832for (i = 0; i < omap_port->channels; i++) {833if (list_empty(&omap_port->rxqueue[i]))834continue;835msg = list_first_entry(&omap_port->rxqueue[i], struct hsi_msg,836link);837list_del(&msg->link);838msg->status = HSI_STATUS_ERROR;839spin_unlock(&omap_port->lock);840msg->complete(msg);841/* Now restart queued reads if any */842ssi_transfer(omap_port, &omap_port->rxqueue[i]);843spin_lock(&omap_port->lock);844}845spin_unlock(&omap_port->lock);846}847848static void ssi_break_complete(struct hsi_port *port)849{850struct omap_ssi_port *omap_port = hsi_port_drvdata(port);851struct hsi_controller *ssi = to_hsi_controller(port->device.parent);852struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);853struct hsi_msg *msg;854struct hsi_msg *tmp;855u32 val;856857dev_dbg(&port->device, "HWBREAK received\n");858859spin_lock(&omap_port->lock);860val = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));861val &= ~SSI_BREAKDETECTED;862writel_relaxed(val, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));863writel_relaxed(0, omap_port->ssr_base + SSI_SSR_BREAK_REG);864writel(SSI_BREAKDETECTED,865omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));866spin_unlock(&omap_port->lock);867868list_for_each_entry_safe(msg, tmp, &omap_port->brkqueue, link) {869msg->status = HSI_STATUS_COMPLETED;870spin_lock(&omap_port->lock);871list_del(&msg->link);872spin_unlock(&omap_port->lock);873msg->complete(msg);874}875876}877878static void ssi_pio_complete(struct hsi_port *port, struct list_head *queue)879{880struct hsi_controller *ssi = to_hsi_controller(port->device.parent);881struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);882struct omap_ssi_port *omap_port = hsi_port_drvdata(port);883struct hsi_msg *msg;884u32 *buf;885u32 reg;886u32 val;887888spin_lock_bh(&omap_port->lock);889msg = list_first_entry(queue, struct hsi_msg, link);890if ((!msg->sgt.nents) || (!msg->sgt.sgl->length)) {891msg->actual_len = 0;892msg->status = HSI_STATUS_PENDING;893}894if (msg->ttype == HSI_MSG_WRITE)895val = SSI_DATAACCEPT(msg->channel);896else897val = SSI_DATAAVAILABLE(msg->channel);898if (msg->status == HSI_STATUS_PROCEEDING) {899buf = sg_virt(msg->sgt.sgl) + msg->actual_len;900if (msg->ttype == HSI_MSG_WRITE)901writel(*buf, omap_port->sst_base +902SSI_SST_BUFFER_CH_REG(msg->channel));903else904*buf = readl(omap_port->ssr_base +905SSI_SSR_BUFFER_CH_REG(msg->channel));906dev_dbg(&port->device, "ch %d ttype %d 0x%08x\n", msg->channel,907msg->ttype, *buf);908msg->actual_len += sizeof(*buf);909if (msg->actual_len >= msg->sgt.sgl->length)910msg->status = HSI_STATUS_COMPLETED;911/*912* Wait for the last written frame to be really sent before913* we call the complete callback914*/915if ((msg->status == HSI_STATUS_PROCEEDING) ||916((msg->status == HSI_STATUS_COMPLETED) &&917(msg->ttype == HSI_MSG_WRITE))) {918writel(val, omap_ssi->sys +919SSI_MPU_STATUS_REG(port->num, 0));920spin_unlock_bh(&omap_port->lock);921922return;923}924925}926/* Transfer completed at this point */927reg = readl(omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));928if (msg->ttype == HSI_MSG_WRITE) {929/* Release clocks for write transfer */930pm_runtime_put_autosuspend(omap_port->pdev);931}932reg &= ~val;933writel_relaxed(reg, omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));934writel_relaxed(val, omap_ssi->sys + SSI_MPU_STATUS_REG(port->num, 0));935list_del(&msg->link);936spin_unlock_bh(&omap_port->lock);937msg->complete(msg);938ssi_transfer(omap_port, queue);939}940941static irqreturn_t ssi_pio_thread(int irq, void *ssi_port)942{943struct hsi_port *port = (struct hsi_port *)ssi_port;944struct hsi_controller *ssi = to_hsi_controller(port->device.parent);945struct omap_ssi_port *omap_port = hsi_port_drvdata(port);946struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);947void __iomem *sys = omap_ssi->sys;948unsigned int ch;949u32 status_reg;950951pm_runtime_get_sync(omap_port->pdev);952953do {954status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));955status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));956957for (ch = 0; ch < omap_port->channels; ch++) {958if (status_reg & SSI_DATAACCEPT(ch))959ssi_pio_complete(port, &omap_port->txqueue[ch]);960if (status_reg & SSI_DATAAVAILABLE(ch))961ssi_pio_complete(port, &omap_port->rxqueue[ch]);962}963if (status_reg & SSI_BREAKDETECTED)964ssi_break_complete(port);965if (status_reg & SSI_ERROROCCURED)966ssi_error(port);967968status_reg = readl(sys + SSI_MPU_STATUS_REG(port->num, 0));969status_reg &= readl(sys + SSI_MPU_ENABLE_REG(port->num, 0));970971/* TODO: sleep if we retry? */972} while (status_reg);973974pm_runtime_put_autosuspend(omap_port->pdev);975976return IRQ_HANDLED;977}978979static irqreturn_t ssi_wake_thread(int irq __maybe_unused, void *ssi_port)980{981struct hsi_port *port = (struct hsi_port *)ssi_port;982struct hsi_controller *ssi = to_hsi_controller(port->device.parent);983struct omap_ssi_port *omap_port = hsi_port_drvdata(port);984struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);985986if (ssi_wakein(port)) {987/**988* We can have a quick High-Low-High transition in the line.989* In such a case if we have long interrupt latencies,990* we can miss the low event or get twice a high event.991* This workaround will avoid breaking the clock reference992* count when such a situation ocurrs.993*/994if (!test_and_set_bit(SSI_WAKE_EN, &omap_port->flags))995pm_runtime_get_sync(omap_port->pdev);996dev_dbg(&ssi->device, "Wake in high\n");997if (omap_port->wktest) { /* FIXME: HACK ! To be removed */998writel(SSI_WAKE(0),999omap_ssi->sys + SSI_SET_WAKE_REG(port->num));1000}1001hsi_event(port, HSI_EVENT_START_RX);1002} else {1003dev_dbg(&ssi->device, "Wake in low\n");1004if (omap_port->wktest) { /* FIXME: HACK ! To be removed */1005writel(SSI_WAKE(0),1006omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));1007}1008hsi_event(port, HSI_EVENT_STOP_RX);1009if (test_and_clear_bit(SSI_WAKE_EN, &omap_port->flags)) {1010pm_runtime_put_autosuspend(omap_port->pdev);1011}1012}10131014return IRQ_HANDLED;1015}10161017static int ssi_port_irq(struct hsi_port *port, struct platform_device *pd)1018{1019struct omap_ssi_port *omap_port = hsi_port_drvdata(port);1020int err;10211022err = platform_get_irq(pd, 0);1023if (err < 0)1024return err;1025omap_port->irq = err;1026err = devm_request_threaded_irq(&port->device, omap_port->irq, NULL,1027ssi_pio_thread, IRQF_ONESHOT, "SSI PORT", port);1028if (err < 0)1029dev_err(&port->device, "Request IRQ %d failed (%d)\n",1030omap_port->irq, err);1031return err;1032}10331034static int ssi_wake_irq(struct hsi_port *port, struct platform_device *pd)1035{1036struct omap_ssi_port *omap_port = hsi_port_drvdata(port);1037int cawake_irq;1038int err;10391040if (!omap_port->wake_gpio) {1041omap_port->wake_irq = -1;1042return 0;1043}10441045cawake_irq = gpiod_to_irq(omap_port->wake_gpio);1046omap_port->wake_irq = cawake_irq;10471048err = devm_request_threaded_irq(&port->device, cawake_irq, NULL,1049ssi_wake_thread,1050IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,1051"SSI cawake", port);1052if (err < 0)1053dev_err(&port->device, "Request Wake in IRQ %d failed %d\n",1054cawake_irq, err);1055err = enable_irq_wake(cawake_irq);1056if (err < 0)1057dev_err(&port->device, "Enable wake on the wakeline in irq %d failed %d\n",1058cawake_irq, err);10591060return err;1061}10621063static void ssi_queues_init(struct omap_ssi_port *omap_port)1064{1065unsigned int ch;10661067for (ch = 0; ch < SSI_MAX_CHANNELS; ch++) {1068INIT_LIST_HEAD(&omap_port->txqueue[ch]);1069INIT_LIST_HEAD(&omap_port->rxqueue[ch]);1070}1071INIT_LIST_HEAD(&omap_port->brkqueue);1072}10731074static int ssi_port_get_iomem(struct platform_device *pd,1075const char *name, void __iomem **pbase, dma_addr_t *phy)1076{1077struct hsi_port *port = platform_get_drvdata(pd);1078struct resource *mem;1079struct resource *ioarea;1080void __iomem *base;10811082mem = platform_get_resource_byname(pd, IORESOURCE_MEM, name);1083if (!mem) {1084dev_err(&pd->dev, "IO memory region missing (%s)\n", name);1085return -ENXIO;1086}1087ioarea = devm_request_mem_region(&port->device, mem->start,1088resource_size(mem), dev_name(&pd->dev));1089if (!ioarea) {1090dev_err(&pd->dev, "%s IO memory region request failed\n",1091mem->name);1092return -ENXIO;1093}1094base = devm_ioremap(&port->device, mem->start, resource_size(mem));1095if (!base) {1096dev_err(&pd->dev, "%s IO remap failed\n", mem->name);1097return -ENXIO;1098}1099*pbase = base;11001101if (phy)1102*phy = mem->start;11031104return 0;1105}11061107static int ssi_port_probe(struct platform_device *pd)1108{1109struct device_node *np = pd->dev.of_node;1110struct hsi_port *port;1111struct omap_ssi_port *omap_port;1112struct hsi_controller *ssi = dev_get_drvdata(pd->dev.parent);1113struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);1114struct gpio_desc *cawake_gpio = NULL;1115u32 port_id;1116int err;11171118dev_dbg(&pd->dev, "init ssi port...\n");11191120if (!ssi->port || !omap_ssi->port) {1121dev_err(&pd->dev, "ssi controller not initialized!\n");1122err = -ENODEV;1123goto error;1124}11251126/* get id of first uninitialized port in controller */1127for (port_id = 0; port_id < ssi->num_ports && omap_ssi->port[port_id];1128port_id++)1129;11301131if (port_id >= ssi->num_ports) {1132dev_err(&pd->dev, "port id out of range!\n");1133err = -ENODEV;1134goto error;1135}11361137port = ssi->port[port_id];11381139if (!np) {1140dev_err(&pd->dev, "missing device tree data\n");1141err = -EINVAL;1142goto error;1143}11441145cawake_gpio = devm_gpiod_get(&pd->dev, "ti,ssi-cawake", GPIOD_IN);1146if (IS_ERR(cawake_gpio)) {1147err = PTR_ERR(cawake_gpio);1148dev_err(&pd->dev, "couldn't get cawake gpio (err=%d)!\n", err);1149goto error;1150}11511152omap_port = devm_kzalloc(&port->device, sizeof(*omap_port), GFP_KERNEL);1153if (!omap_port) {1154err = -ENOMEM;1155goto error;1156}1157omap_port->wake_gpio = cawake_gpio;1158omap_port->pdev = &pd->dev;1159omap_port->port_id = port_id;11601161INIT_DEFERRABLE_WORK(&omap_port->errqueue_work, ssi_process_errqueue);1162INIT_WORK(&omap_port->work, start_tx_work);11631164/* initialize HSI port */1165port->async = ssi_async;1166port->setup = ssi_setup;1167port->flush = ssi_flush;1168port->start_tx = ssi_start_tx;1169port->stop_tx = ssi_stop_tx;1170port->release = ssi_release;1171hsi_port_set_drvdata(port, omap_port);1172omap_ssi->port[port_id] = omap_port;11731174platform_set_drvdata(pd, port);11751176err = ssi_port_get_iomem(pd, "tx", &omap_port->sst_base,1177&omap_port->sst_dma);1178if (err < 0)1179goto error;1180err = ssi_port_get_iomem(pd, "rx", &omap_port->ssr_base,1181&omap_port->ssr_dma);1182if (err < 0)1183goto error;11841185err = ssi_port_irq(port, pd);1186if (err < 0)1187goto error;1188err = ssi_wake_irq(port, pd);1189if (err < 0)1190goto error;11911192ssi_queues_init(omap_port);1193spin_lock_init(&omap_port->lock);1194spin_lock_init(&omap_port->wk_lock);1195omap_port->dev = &port->device;11961197pm_runtime_use_autosuspend(omap_port->pdev);1198pm_runtime_set_autosuspend_delay(omap_port->pdev, 250);1199pm_runtime_enable(omap_port->pdev);12001201#ifdef CONFIG_DEBUG_FS1202ssi_debug_add_port(omap_port, omap_ssi->dir);1203#endif12041205hsi_add_clients_from_dt(port, np);12061207dev_info(&pd->dev, "ssi port %u successfully initialized\n", port_id);12081209return 0;12101211error:1212return err;1213}12141215static void ssi_port_remove(struct platform_device *pd)1216{1217struct hsi_port *port = platform_get_drvdata(pd);1218struct omap_ssi_port *omap_port = hsi_port_drvdata(port);1219struct hsi_controller *ssi = to_hsi_controller(port->device.parent);1220struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);12211222#ifdef CONFIG_DEBUG_FS1223ssi_debug_remove_port(port);1224#endif12251226cancel_delayed_work_sync(&omap_port->errqueue_work);12271228hsi_port_unregister_clients(port);12291230port->async = hsi_dummy_msg;1231port->setup = hsi_dummy_cl;1232port->flush = hsi_dummy_cl;1233port->start_tx = hsi_dummy_cl;1234port->stop_tx = hsi_dummy_cl;1235port->release = hsi_dummy_cl;12361237omap_ssi->port[omap_port->port_id] = NULL;1238platform_set_drvdata(pd, NULL);12391240pm_runtime_dont_use_autosuspend(&pd->dev);1241pm_runtime_disable(&pd->dev);1242}12431244static int ssi_restore_divisor(struct omap_ssi_port *omap_port)1245{1246writel_relaxed(omap_port->sst.divisor,1247omap_port->sst_base + SSI_SST_DIVISOR_REG);12481249return 0;1250}12511252void omap_ssi_port_update_fclk(struct hsi_controller *ssi,1253struct omap_ssi_port *omap_port)1254{1255/* update divisor */1256u32 div = ssi_calculate_div(ssi);1257omap_port->sst.divisor = div;1258ssi_restore_divisor(omap_port);1259}12601261#ifdef CONFIG_PM1262static int ssi_save_port_ctx(struct omap_ssi_port *omap_port)1263{1264struct hsi_port *port = to_hsi_port(omap_port->dev);1265struct hsi_controller *ssi = to_hsi_controller(port->device.parent);1266struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);12671268omap_port->sys_mpu_enable = readl(omap_ssi->sys +1269SSI_MPU_ENABLE_REG(port->num, 0));12701271return 0;1272}12731274static int ssi_restore_port_ctx(struct omap_ssi_port *omap_port)1275{1276struct hsi_port *port = to_hsi_port(omap_port->dev);1277struct hsi_controller *ssi = to_hsi_controller(port->device.parent);1278struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);1279void __iomem *base;12801281writel_relaxed(omap_port->sys_mpu_enable,1282omap_ssi->sys + SSI_MPU_ENABLE_REG(port->num, 0));12831284/* SST context */1285base = omap_port->sst_base;1286writel_relaxed(omap_port->sst.frame_size, base + SSI_SST_FRAMESIZE_REG);1287writel_relaxed(omap_port->sst.channels, base + SSI_SST_CHANNELS_REG);1288writel_relaxed(omap_port->sst.arb_mode, base + SSI_SST_ARBMODE_REG);12891290/* SSR context */1291base = omap_port->ssr_base;1292writel_relaxed(omap_port->ssr.frame_size, base + SSI_SSR_FRAMESIZE_REG);1293writel_relaxed(omap_port->ssr.channels, base + SSI_SSR_CHANNELS_REG);1294writel_relaxed(omap_port->ssr.timeout, base + SSI_SSR_TIMEOUT_REG);12951296return 0;1297}12981299static int ssi_restore_port_mode(struct omap_ssi_port *omap_port)1300{1301u32 mode;13021303writel_relaxed(omap_port->sst.mode,1304omap_port->sst_base + SSI_SST_MODE_REG);1305writel_relaxed(omap_port->ssr.mode,1306omap_port->ssr_base + SSI_SSR_MODE_REG);1307/* OCP barrier */1308mode = readl(omap_port->ssr_base + SSI_SSR_MODE_REG);13091310return 0;1311}13121313static int omap_ssi_port_runtime_suspend(struct device *dev)1314{1315struct hsi_port *port = dev_get_drvdata(dev);1316struct omap_ssi_port *omap_port = hsi_port_drvdata(port);1317struct hsi_controller *ssi = to_hsi_controller(port->device.parent);1318struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);13191320dev_dbg(dev, "port runtime suspend!\n");13211322ssi_set_port_mode(omap_port, SSI_MODE_SLEEP);1323if (omap_ssi->get_loss)1324omap_port->loss_count =1325omap_ssi->get_loss(ssi->device.parent);1326ssi_save_port_ctx(omap_port);13271328return 0;1329}13301331static int omap_ssi_port_runtime_resume(struct device *dev)1332{1333struct hsi_port *port = dev_get_drvdata(dev);1334struct omap_ssi_port *omap_port = hsi_port_drvdata(port);1335struct hsi_controller *ssi = to_hsi_controller(port->device.parent);1336struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);13371338dev_dbg(dev, "port runtime resume!\n");13391340if ((omap_ssi->get_loss) && (omap_port->loss_count ==1341omap_ssi->get_loss(ssi->device.parent)))1342goto mode; /* We always need to restore the mode & TX divisor */13431344ssi_restore_port_ctx(omap_port);13451346mode:1347ssi_restore_divisor(omap_port);1348ssi_restore_port_mode(omap_port);13491350return 0;1351}13521353static const struct dev_pm_ops omap_ssi_port_pm_ops = {1354SET_RUNTIME_PM_OPS(omap_ssi_port_runtime_suspend,1355omap_ssi_port_runtime_resume, NULL)1356};13571358#define DEV_PM_OPS (&omap_ssi_port_pm_ops)1359#else1360#define DEV_PM_OPS NULL1361#endif136213631364#ifdef CONFIG_OF1365static const struct of_device_id omap_ssi_port_of_match[] = {1366{ .compatible = "ti,omap3-ssi-port", },1367{},1368};1369MODULE_DEVICE_TABLE(of, omap_ssi_port_of_match);1370#else1371#define omap_ssi_port_of_match NULL1372#endif13731374struct platform_driver ssi_port_pdriver = {1375.probe = ssi_port_probe,1376.remove = ssi_port_remove,1377.driver = {1378.name = "omap_ssi_port",1379.of_match_table = omap_ssi_port_of_match,1380.pm = DEV_PM_OPS,1381},1382};138313841385