1*ad7fcbc3SSagar Dharia // SPDX-License-Identifier: GPL-2.0 2*ad7fcbc3SSagar Dharia /* 3*ad7fcbc3SSagar Dharia * Copyright (c) 2011-2017, The Linux Foundation 4*ad7fcbc3SSagar Dharia */ 5*ad7fcbc3SSagar Dharia 6*ad7fcbc3SSagar Dharia #include <linux/irq.h> 7*ad7fcbc3SSagar Dharia #include <linux/kernel.h> 8*ad7fcbc3SSagar Dharia #include <linux/init.h> 9*ad7fcbc3SSagar Dharia #include <linux/slab.h> 10*ad7fcbc3SSagar Dharia #include <linux/io.h> 11*ad7fcbc3SSagar Dharia #include <linux/interrupt.h> 12*ad7fcbc3SSagar Dharia #include <linux/platform_device.h> 13*ad7fcbc3SSagar Dharia #include <linux/delay.h> 14*ad7fcbc3SSagar Dharia #include <linux/clk.h> 15*ad7fcbc3SSagar Dharia #include <linux/of.h> 16*ad7fcbc3SSagar Dharia #include <linux/dma-mapping.h> 17*ad7fcbc3SSagar Dharia #include "slimbus.h" 18*ad7fcbc3SSagar Dharia 19*ad7fcbc3SSagar Dharia /* Manager registers */ 20*ad7fcbc3SSagar Dharia #define MGR_CFG 0x200 21*ad7fcbc3SSagar Dharia #define MGR_STATUS 0x204 22*ad7fcbc3SSagar Dharia #define MGR_INT_EN 0x210 23*ad7fcbc3SSagar Dharia #define MGR_INT_STAT 0x214 24*ad7fcbc3SSagar Dharia #define MGR_INT_CLR 0x218 25*ad7fcbc3SSagar Dharia #define MGR_TX_MSG 0x230 26*ad7fcbc3SSagar Dharia #define MGR_RX_MSG 0x270 27*ad7fcbc3SSagar Dharia #define MGR_IE_STAT 0x2F0 28*ad7fcbc3SSagar Dharia #define MGR_VE_STAT 0x300 29*ad7fcbc3SSagar Dharia #define MGR_CFG_ENABLE 1 30*ad7fcbc3SSagar Dharia 31*ad7fcbc3SSagar Dharia /* Framer registers */ 32*ad7fcbc3SSagar Dharia #define FRM_CFG 0x400 33*ad7fcbc3SSagar Dharia #define FRM_STAT 0x404 34*ad7fcbc3SSagar Dharia #define FRM_INT_EN 0x410 35*ad7fcbc3SSagar Dharia #define FRM_INT_STAT 0x414 36*ad7fcbc3SSagar Dharia #define FRM_INT_CLR 0x418 37*ad7fcbc3SSagar Dharia #define FRM_WAKEUP 0x41C 38*ad7fcbc3SSagar Dharia #define FRM_CLKCTL_DONE 0x420 39*ad7fcbc3SSagar Dharia #define FRM_IE_STAT 0x430 40*ad7fcbc3SSagar Dharia #define FRM_VE_STAT 0x440 41*ad7fcbc3SSagar Dharia 42*ad7fcbc3SSagar Dharia /* Interface registers */ 43*ad7fcbc3SSagar Dharia #define INTF_CFG 0x600 44*ad7fcbc3SSagar Dharia #define INTF_STAT 0x604 45*ad7fcbc3SSagar Dharia #define INTF_INT_EN 0x610 46*ad7fcbc3SSagar Dharia #define INTF_INT_STAT 0x614 47*ad7fcbc3SSagar Dharia #define INTF_INT_CLR 0x618 48*ad7fcbc3SSagar Dharia #define INTF_IE_STAT 0x630 49*ad7fcbc3SSagar Dharia #define INTF_VE_STAT 0x640 50*ad7fcbc3SSagar Dharia 51*ad7fcbc3SSagar Dharia /* Interrupt status bits */ 52*ad7fcbc3SSagar Dharia #define MGR_INT_TX_NACKED_2 BIT(25) 53*ad7fcbc3SSagar Dharia #define MGR_INT_MSG_BUF_CONTE BIT(26) 54*ad7fcbc3SSagar Dharia #define MGR_INT_RX_MSG_RCVD BIT(30) 55*ad7fcbc3SSagar Dharia #define MGR_INT_TX_MSG_SENT BIT(31) 56*ad7fcbc3SSagar Dharia 57*ad7fcbc3SSagar Dharia /* Framer config register settings */ 58*ad7fcbc3SSagar Dharia #define FRM_ACTIVE 1 59*ad7fcbc3SSagar Dharia #define CLK_GEAR 7 60*ad7fcbc3SSagar Dharia #define ROOT_FREQ 11 61*ad7fcbc3SSagar Dharia #define REF_CLK_GEAR 15 62*ad7fcbc3SSagar Dharia #define INTR_WAKE 19 63*ad7fcbc3SSagar Dharia 64*ad7fcbc3SSagar Dharia #define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \ 65*ad7fcbc3SSagar Dharia ((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16)) 66*ad7fcbc3SSagar Dharia 67*ad7fcbc3SSagar Dharia #define SLIM_ROOT_FREQ 24576000 68*ad7fcbc3SSagar Dharia 69*ad7fcbc3SSagar Dharia /* MAX message size over control channel */ 70*ad7fcbc3SSagar Dharia #define SLIM_MSGQ_BUF_LEN 40 71*ad7fcbc3SSagar Dharia #define QCOM_TX_MSGS 2 72*ad7fcbc3SSagar Dharia #define QCOM_RX_MSGS 8 73*ad7fcbc3SSagar Dharia #define QCOM_BUF_ALLOC_RETRIES 10 74*ad7fcbc3SSagar Dharia 75*ad7fcbc3SSagar Dharia #define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r)) 76*ad7fcbc3SSagar Dharia 77*ad7fcbc3SSagar Dharia /* V2 Component registers */ 78*ad7fcbc3SSagar Dharia #define CFG_PORT_V2(r) ((r ## _V2)) 79*ad7fcbc3SSagar Dharia #define COMP_CFG_V2 4 80*ad7fcbc3SSagar Dharia #define COMP_TRUST_CFG_V2 0x3000 81*ad7fcbc3SSagar Dharia 82*ad7fcbc3SSagar Dharia /* V1 Component registers */ 83*ad7fcbc3SSagar Dharia #define CFG_PORT_V1(r) ((r ## _V1)) 84*ad7fcbc3SSagar Dharia #define COMP_CFG_V1 0 85*ad7fcbc3SSagar Dharia #define COMP_TRUST_CFG_V1 0x14 86*ad7fcbc3SSagar Dharia 87*ad7fcbc3SSagar Dharia /* Resource group info for manager, and non-ported generic device-components */ 88*ad7fcbc3SSagar Dharia #define EE_MGR_RSC_GRP (1 << 10) 89*ad7fcbc3SSagar Dharia #define EE_NGD_2 (2 << 6) 90*ad7fcbc3SSagar Dharia #define EE_NGD_1 0 91*ad7fcbc3SSagar Dharia 92*ad7fcbc3SSagar Dharia struct slim_ctrl_buf { 93*ad7fcbc3SSagar Dharia void *base; 94*ad7fcbc3SSagar Dharia phys_addr_t phy; 95*ad7fcbc3SSagar Dharia spinlock_t lock; 96*ad7fcbc3SSagar Dharia int head; 97*ad7fcbc3SSagar Dharia int tail; 98*ad7fcbc3SSagar Dharia int sl_sz; 99*ad7fcbc3SSagar Dharia int n; 100*ad7fcbc3SSagar Dharia }; 101*ad7fcbc3SSagar Dharia 102*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl { 103*ad7fcbc3SSagar Dharia struct slim_controller ctrl; 104*ad7fcbc3SSagar Dharia struct slim_framer framer; 105*ad7fcbc3SSagar Dharia struct device *dev; 106*ad7fcbc3SSagar Dharia void __iomem *base; 107*ad7fcbc3SSagar Dharia void __iomem *slew_reg; 108*ad7fcbc3SSagar Dharia 109*ad7fcbc3SSagar Dharia struct slim_ctrl_buf rx; 110*ad7fcbc3SSagar Dharia struct slim_ctrl_buf tx; 111*ad7fcbc3SSagar Dharia 112*ad7fcbc3SSagar Dharia struct completion **wr_comp; 113*ad7fcbc3SSagar Dharia int irq; 114*ad7fcbc3SSagar Dharia struct workqueue_struct *rxwq; 115*ad7fcbc3SSagar Dharia struct work_struct wd; 116*ad7fcbc3SSagar Dharia struct clk *rclk; 117*ad7fcbc3SSagar Dharia struct clk *hclk; 118*ad7fcbc3SSagar Dharia }; 119*ad7fcbc3SSagar Dharia 120*ad7fcbc3SSagar Dharia static void qcom_slim_queue_tx(struct qcom_slim_ctrl *ctrl, void *buf, 121*ad7fcbc3SSagar Dharia u8 len, u32 tx_reg) 122*ad7fcbc3SSagar Dharia { 123*ad7fcbc3SSagar Dharia int count = (len + 3) >> 2; 124*ad7fcbc3SSagar Dharia 125*ad7fcbc3SSagar Dharia __iowrite32_copy(ctrl->base + tx_reg, buf, count); 126*ad7fcbc3SSagar Dharia 127*ad7fcbc3SSagar Dharia /* Ensure Oder of subsequent writes */ 128*ad7fcbc3SSagar Dharia mb(); 129*ad7fcbc3SSagar Dharia } 130*ad7fcbc3SSagar Dharia 131*ad7fcbc3SSagar Dharia static void *slim_alloc_rxbuf(struct qcom_slim_ctrl *ctrl) 132*ad7fcbc3SSagar Dharia { 133*ad7fcbc3SSagar Dharia unsigned long flags; 134*ad7fcbc3SSagar Dharia int idx; 135*ad7fcbc3SSagar Dharia 136*ad7fcbc3SSagar Dharia spin_lock_irqsave(&ctrl->rx.lock, flags); 137*ad7fcbc3SSagar Dharia if ((ctrl->rx.tail + 1) % ctrl->rx.n == ctrl->rx.head) { 138*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->rx.lock, flags); 139*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "RX QUEUE full!"); 140*ad7fcbc3SSagar Dharia return NULL; 141*ad7fcbc3SSagar Dharia } 142*ad7fcbc3SSagar Dharia idx = ctrl->rx.tail; 143*ad7fcbc3SSagar Dharia ctrl->rx.tail = (ctrl->rx.tail + 1) % ctrl->rx.n; 144*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->rx.lock, flags); 145*ad7fcbc3SSagar Dharia 146*ad7fcbc3SSagar Dharia return ctrl->rx.base + (idx * ctrl->rx.sl_sz); 147*ad7fcbc3SSagar Dharia } 148*ad7fcbc3SSagar Dharia 149*ad7fcbc3SSagar Dharia void slim_ack_txn(struct qcom_slim_ctrl *ctrl, int err) 150*ad7fcbc3SSagar Dharia { 151*ad7fcbc3SSagar Dharia struct completion *comp; 152*ad7fcbc3SSagar Dharia unsigned long flags; 153*ad7fcbc3SSagar Dharia int idx; 154*ad7fcbc3SSagar Dharia 155*ad7fcbc3SSagar Dharia spin_lock_irqsave(&ctrl->tx.lock, flags); 156*ad7fcbc3SSagar Dharia idx = ctrl->tx.head; 157*ad7fcbc3SSagar Dharia ctrl->tx.head = (ctrl->tx.head + 1) % ctrl->tx.n; 158*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->tx.lock, flags); 159*ad7fcbc3SSagar Dharia 160*ad7fcbc3SSagar Dharia comp = ctrl->wr_comp[idx]; 161*ad7fcbc3SSagar Dharia ctrl->wr_comp[idx] = NULL; 162*ad7fcbc3SSagar Dharia 163*ad7fcbc3SSagar Dharia complete(comp); 164*ad7fcbc3SSagar Dharia } 165*ad7fcbc3SSagar Dharia 166*ad7fcbc3SSagar Dharia static irqreturn_t qcom_slim_handle_tx_irq(struct qcom_slim_ctrl *ctrl, 167*ad7fcbc3SSagar Dharia u32 stat) 168*ad7fcbc3SSagar Dharia { 169*ad7fcbc3SSagar Dharia int err = 0; 170*ad7fcbc3SSagar Dharia 171*ad7fcbc3SSagar Dharia if (stat & MGR_INT_TX_MSG_SENT) 172*ad7fcbc3SSagar Dharia writel_relaxed(MGR_INT_TX_MSG_SENT, 173*ad7fcbc3SSagar Dharia ctrl->base + MGR_INT_CLR); 174*ad7fcbc3SSagar Dharia 175*ad7fcbc3SSagar Dharia if (stat & MGR_INT_TX_NACKED_2) { 176*ad7fcbc3SSagar Dharia u32 mgr_stat = readl_relaxed(ctrl->base + MGR_STATUS); 177*ad7fcbc3SSagar Dharia u32 mgr_ie_stat = readl_relaxed(ctrl->base + MGR_IE_STAT); 178*ad7fcbc3SSagar Dharia u32 frm_stat = readl_relaxed(ctrl->base + FRM_STAT); 179*ad7fcbc3SSagar Dharia u32 frm_cfg = readl_relaxed(ctrl->base + FRM_CFG); 180*ad7fcbc3SSagar Dharia u32 frm_intr_stat = readl_relaxed(ctrl->base + FRM_INT_STAT); 181*ad7fcbc3SSagar Dharia u32 frm_ie_stat = readl_relaxed(ctrl->base + FRM_IE_STAT); 182*ad7fcbc3SSagar Dharia u32 intf_stat = readl_relaxed(ctrl->base + INTF_STAT); 183*ad7fcbc3SSagar Dharia u32 intf_intr_stat = readl_relaxed(ctrl->base + INTF_INT_STAT); 184*ad7fcbc3SSagar Dharia u32 intf_ie_stat = readl_relaxed(ctrl->base + INTF_IE_STAT); 185*ad7fcbc3SSagar Dharia 186*ad7fcbc3SSagar Dharia writel_relaxed(MGR_INT_TX_NACKED_2, ctrl->base + MGR_INT_CLR); 187*ad7fcbc3SSagar Dharia 188*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack MGR:int:0x%x, stat:0x%x\n", 189*ad7fcbc3SSagar Dharia stat, mgr_stat); 190*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack MGR:ie:0x%x\n", mgr_ie_stat); 191*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack FRM:int:0x%x, stat:0x%x\n", 192*ad7fcbc3SSagar Dharia frm_intr_stat, frm_stat); 193*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack FRM:cfg:0x%x, ie:0x%x\n", 194*ad7fcbc3SSagar Dharia frm_cfg, frm_ie_stat); 195*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack INTF:intr:0x%x, stat:0x%x\n", 196*ad7fcbc3SSagar Dharia intf_intr_stat, intf_stat); 197*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX Nack INTF:ie:0x%x\n", 198*ad7fcbc3SSagar Dharia intf_ie_stat); 199*ad7fcbc3SSagar Dharia err = -ENOTCONN; 200*ad7fcbc3SSagar Dharia } 201*ad7fcbc3SSagar Dharia 202*ad7fcbc3SSagar Dharia slim_ack_txn(ctrl, err); 203*ad7fcbc3SSagar Dharia 204*ad7fcbc3SSagar Dharia return IRQ_HANDLED; 205*ad7fcbc3SSagar Dharia } 206*ad7fcbc3SSagar Dharia 207*ad7fcbc3SSagar Dharia static irqreturn_t qcom_slim_handle_rx_irq(struct qcom_slim_ctrl *ctrl, 208*ad7fcbc3SSagar Dharia u32 stat) 209*ad7fcbc3SSagar Dharia { 210*ad7fcbc3SSagar Dharia u32 *rx_buf, pkt[10]; 211*ad7fcbc3SSagar Dharia bool q_rx = false; 212*ad7fcbc3SSagar Dharia u8 mc, mt, len; 213*ad7fcbc3SSagar Dharia 214*ad7fcbc3SSagar Dharia pkt[0] = readl_relaxed(ctrl->base + MGR_RX_MSG); 215*ad7fcbc3SSagar Dharia mt = SLIM_HEADER_GET_MT(pkt[0]); 216*ad7fcbc3SSagar Dharia len = SLIM_HEADER_GET_RL(pkt[0]); 217*ad7fcbc3SSagar Dharia mc = SLIM_HEADER_GET_MC(pkt[0]>>8); 218*ad7fcbc3SSagar Dharia 219*ad7fcbc3SSagar Dharia /* 220*ad7fcbc3SSagar Dharia * this message cannot be handled by ISR, so 221*ad7fcbc3SSagar Dharia * let work-queue handle it 222*ad7fcbc3SSagar Dharia */ 223*ad7fcbc3SSagar Dharia if (mt == SLIM_MSG_MT_CORE && mc == SLIM_MSG_MC_REPORT_PRESENT) { 224*ad7fcbc3SSagar Dharia rx_buf = (u32 *)slim_alloc_rxbuf(ctrl); 225*ad7fcbc3SSagar Dharia if (!rx_buf) { 226*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "dropping RX:0x%x due to RX full\n", 227*ad7fcbc3SSagar Dharia pkt[0]); 228*ad7fcbc3SSagar Dharia goto rx_ret_irq; 229*ad7fcbc3SSagar Dharia } 230*ad7fcbc3SSagar Dharia rx_buf[0] = pkt[0]; 231*ad7fcbc3SSagar Dharia 232*ad7fcbc3SSagar Dharia } else { 233*ad7fcbc3SSagar Dharia rx_buf = pkt; 234*ad7fcbc3SSagar Dharia } 235*ad7fcbc3SSagar Dharia 236*ad7fcbc3SSagar Dharia __ioread32_copy(rx_buf + 1, ctrl->base + MGR_RX_MSG + 4, 237*ad7fcbc3SSagar Dharia DIV_ROUND_UP(len, 4)); 238*ad7fcbc3SSagar Dharia 239*ad7fcbc3SSagar Dharia switch (mc) { 240*ad7fcbc3SSagar Dharia 241*ad7fcbc3SSagar Dharia case SLIM_MSG_MC_REPORT_PRESENT: 242*ad7fcbc3SSagar Dharia q_rx = true; 243*ad7fcbc3SSagar Dharia break; 244*ad7fcbc3SSagar Dharia case SLIM_MSG_MC_REPLY_INFORMATION: 245*ad7fcbc3SSagar Dharia case SLIM_MSG_MC_REPLY_VALUE: 246*ad7fcbc3SSagar Dharia slim_msg_response(&ctrl->ctrl, (u8 *)(rx_buf + 1), 247*ad7fcbc3SSagar Dharia (u8)(*rx_buf >> 24), (len - 4)); 248*ad7fcbc3SSagar Dharia break; 249*ad7fcbc3SSagar Dharia default: 250*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "unsupported MC,%x MT:%x\n", 251*ad7fcbc3SSagar Dharia mc, mt); 252*ad7fcbc3SSagar Dharia break; 253*ad7fcbc3SSagar Dharia } 254*ad7fcbc3SSagar Dharia rx_ret_irq: 255*ad7fcbc3SSagar Dharia writel(MGR_INT_RX_MSG_RCVD, ctrl->base + 256*ad7fcbc3SSagar Dharia MGR_INT_CLR); 257*ad7fcbc3SSagar Dharia if (q_rx) 258*ad7fcbc3SSagar Dharia queue_work(ctrl->rxwq, &ctrl->wd); 259*ad7fcbc3SSagar Dharia 260*ad7fcbc3SSagar Dharia return IRQ_HANDLED; 261*ad7fcbc3SSagar Dharia } 262*ad7fcbc3SSagar Dharia 263*ad7fcbc3SSagar Dharia static irqreturn_t qcom_slim_interrupt(int irq, void *d) 264*ad7fcbc3SSagar Dharia { 265*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl = d; 266*ad7fcbc3SSagar Dharia u32 stat = readl_relaxed(ctrl->base + MGR_INT_STAT); 267*ad7fcbc3SSagar Dharia int ret = IRQ_NONE; 268*ad7fcbc3SSagar Dharia 269*ad7fcbc3SSagar Dharia if (stat & MGR_INT_TX_MSG_SENT || stat & MGR_INT_TX_NACKED_2) 270*ad7fcbc3SSagar Dharia ret = qcom_slim_handle_tx_irq(ctrl, stat); 271*ad7fcbc3SSagar Dharia 272*ad7fcbc3SSagar Dharia if (stat & MGR_INT_RX_MSG_RCVD) 273*ad7fcbc3SSagar Dharia ret = qcom_slim_handle_rx_irq(ctrl, stat); 274*ad7fcbc3SSagar Dharia 275*ad7fcbc3SSagar Dharia return ret; 276*ad7fcbc3SSagar Dharia } 277*ad7fcbc3SSagar Dharia 278*ad7fcbc3SSagar Dharia void *slim_alloc_txbuf(struct qcom_slim_ctrl *ctrl, struct slim_msg_txn *txn, 279*ad7fcbc3SSagar Dharia struct completion *done) 280*ad7fcbc3SSagar Dharia { 281*ad7fcbc3SSagar Dharia unsigned long flags; 282*ad7fcbc3SSagar Dharia int idx; 283*ad7fcbc3SSagar Dharia 284*ad7fcbc3SSagar Dharia spin_lock_irqsave(&ctrl->tx.lock, flags); 285*ad7fcbc3SSagar Dharia if (((ctrl->tx.head + 1) % ctrl->tx.n) == ctrl->tx.tail) { 286*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->tx.lock, flags); 287*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "controller TX buf unavailable"); 288*ad7fcbc3SSagar Dharia return NULL; 289*ad7fcbc3SSagar Dharia } 290*ad7fcbc3SSagar Dharia idx = ctrl->tx.tail; 291*ad7fcbc3SSagar Dharia ctrl->wr_comp[idx] = done; 292*ad7fcbc3SSagar Dharia ctrl->tx.tail = (ctrl->tx.tail + 1) % ctrl->tx.n; 293*ad7fcbc3SSagar Dharia 294*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->tx.lock, flags); 295*ad7fcbc3SSagar Dharia 296*ad7fcbc3SSagar Dharia return ctrl->tx.base + (idx * ctrl->tx.sl_sz); 297*ad7fcbc3SSagar Dharia } 298*ad7fcbc3SSagar Dharia 299*ad7fcbc3SSagar Dharia 300*ad7fcbc3SSagar Dharia static int qcom_xfer_msg(struct slim_controller *sctrl, 301*ad7fcbc3SSagar Dharia struct slim_msg_txn *txn) 302*ad7fcbc3SSagar Dharia { 303*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev); 304*ad7fcbc3SSagar Dharia DECLARE_COMPLETION_ONSTACK(done); 305*ad7fcbc3SSagar Dharia void *pbuf = slim_alloc_txbuf(ctrl, txn, &done); 306*ad7fcbc3SSagar Dharia unsigned long ms = txn->rl + HZ; 307*ad7fcbc3SSagar Dharia u8 *puc; 308*ad7fcbc3SSagar Dharia int ret = 0, timeout, retries = QCOM_BUF_ALLOC_RETRIES; 309*ad7fcbc3SSagar Dharia u8 la = txn->la; 310*ad7fcbc3SSagar Dharia u32 *head; 311*ad7fcbc3SSagar Dharia /* HW expects length field to be excluded */ 312*ad7fcbc3SSagar Dharia txn->rl--; 313*ad7fcbc3SSagar Dharia 314*ad7fcbc3SSagar Dharia /* spin till buffer is made available */ 315*ad7fcbc3SSagar Dharia if (!pbuf) { 316*ad7fcbc3SSagar Dharia while (retries--) { 317*ad7fcbc3SSagar Dharia usleep_range(10000, 15000); 318*ad7fcbc3SSagar Dharia pbuf = slim_alloc_txbuf(ctrl, txn, &done); 319*ad7fcbc3SSagar Dharia if (pbuf) 320*ad7fcbc3SSagar Dharia break; 321*ad7fcbc3SSagar Dharia } 322*ad7fcbc3SSagar Dharia } 323*ad7fcbc3SSagar Dharia 324*ad7fcbc3SSagar Dharia if (!retries && !pbuf) 325*ad7fcbc3SSagar Dharia return -ENOMEM; 326*ad7fcbc3SSagar Dharia 327*ad7fcbc3SSagar Dharia puc = (u8 *)pbuf; 328*ad7fcbc3SSagar Dharia head = (u32 *)pbuf; 329*ad7fcbc3SSagar Dharia 330*ad7fcbc3SSagar Dharia if (txn->dt == SLIM_MSG_DEST_LOGICALADDR) { 331*ad7fcbc3SSagar Dharia *head = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, 332*ad7fcbc3SSagar Dharia txn->mc, 0, la); 333*ad7fcbc3SSagar Dharia puc += 3; 334*ad7fcbc3SSagar Dharia } else { 335*ad7fcbc3SSagar Dharia *head = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, 336*ad7fcbc3SSagar Dharia txn->mc, 1, la); 337*ad7fcbc3SSagar Dharia puc += 2; 338*ad7fcbc3SSagar Dharia } 339*ad7fcbc3SSagar Dharia 340*ad7fcbc3SSagar Dharia if (slim_tid_txn(txn->mt, txn->mc)) 341*ad7fcbc3SSagar Dharia *(puc++) = txn->tid; 342*ad7fcbc3SSagar Dharia 343*ad7fcbc3SSagar Dharia if (slim_ec_txn(txn->mt, txn->mc)) { 344*ad7fcbc3SSagar Dharia *(puc++) = (txn->ec & 0xFF); 345*ad7fcbc3SSagar Dharia *(puc++) = (txn->ec >> 8) & 0xFF; 346*ad7fcbc3SSagar Dharia } 347*ad7fcbc3SSagar Dharia 348*ad7fcbc3SSagar Dharia if (txn->msg && txn->msg->wbuf) 349*ad7fcbc3SSagar Dharia memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes); 350*ad7fcbc3SSagar Dharia 351*ad7fcbc3SSagar Dharia qcom_slim_queue_tx(ctrl, head, txn->rl, MGR_TX_MSG); 352*ad7fcbc3SSagar Dharia timeout = wait_for_completion_timeout(&done, msecs_to_jiffies(ms)); 353*ad7fcbc3SSagar Dharia 354*ad7fcbc3SSagar Dharia if (!timeout) { 355*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc, 356*ad7fcbc3SSagar Dharia txn->mt); 357*ad7fcbc3SSagar Dharia ret = -ETIMEDOUT; 358*ad7fcbc3SSagar Dharia } 359*ad7fcbc3SSagar Dharia 360*ad7fcbc3SSagar Dharia return ret; 361*ad7fcbc3SSagar Dharia 362*ad7fcbc3SSagar Dharia } 363*ad7fcbc3SSagar Dharia 364*ad7fcbc3SSagar Dharia static int qcom_set_laddr(struct slim_controller *sctrl, 365*ad7fcbc3SSagar Dharia struct slim_eaddr *ead, u8 laddr) 366*ad7fcbc3SSagar Dharia { 367*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev); 368*ad7fcbc3SSagar Dharia struct { 369*ad7fcbc3SSagar Dharia __be16 manf_id; 370*ad7fcbc3SSagar Dharia __be16 prod_code; 371*ad7fcbc3SSagar Dharia u8 dev_index; 372*ad7fcbc3SSagar Dharia u8 instance; 373*ad7fcbc3SSagar Dharia u8 laddr; 374*ad7fcbc3SSagar Dharia } __packed p; 375*ad7fcbc3SSagar Dharia struct slim_val_inf msg = {0}; 376*ad7fcbc3SSagar Dharia DEFINE_SLIM_EDEST_TXN(txn, SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS, 377*ad7fcbc3SSagar Dharia 10, laddr, &msg); 378*ad7fcbc3SSagar Dharia int ret; 379*ad7fcbc3SSagar Dharia 380*ad7fcbc3SSagar Dharia p.manf_id = cpu_to_be16(ead->manf_id); 381*ad7fcbc3SSagar Dharia p.prod_code = cpu_to_be16(ead->prod_code); 382*ad7fcbc3SSagar Dharia p.dev_index = ead->dev_index; 383*ad7fcbc3SSagar Dharia p.instance = ead->instance; 384*ad7fcbc3SSagar Dharia p.laddr = laddr; 385*ad7fcbc3SSagar Dharia 386*ad7fcbc3SSagar Dharia msg.wbuf = (void *)&p; 387*ad7fcbc3SSagar Dharia msg.num_bytes = 7; 388*ad7fcbc3SSagar Dharia ret = slim_do_transfer(&ctrl->ctrl, &txn); 389*ad7fcbc3SSagar Dharia 390*ad7fcbc3SSagar Dharia if (ret) 391*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "set LA:0x%x failed:ret:%d\n", 392*ad7fcbc3SSagar Dharia laddr, ret); 393*ad7fcbc3SSagar Dharia return ret; 394*ad7fcbc3SSagar Dharia } 395*ad7fcbc3SSagar Dharia 396*ad7fcbc3SSagar Dharia static int slim_get_current_rxbuf(struct qcom_slim_ctrl *ctrl, void *buf) 397*ad7fcbc3SSagar Dharia { 398*ad7fcbc3SSagar Dharia unsigned long flags; 399*ad7fcbc3SSagar Dharia 400*ad7fcbc3SSagar Dharia spin_lock_irqsave(&ctrl->rx.lock, flags); 401*ad7fcbc3SSagar Dharia if (ctrl->rx.tail == ctrl->rx.head) { 402*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->rx.lock, flags); 403*ad7fcbc3SSagar Dharia return -ENODATA; 404*ad7fcbc3SSagar Dharia } 405*ad7fcbc3SSagar Dharia memcpy(buf, ctrl->rx.base + (ctrl->rx.head * ctrl->rx.sl_sz), 406*ad7fcbc3SSagar Dharia ctrl->rx.sl_sz); 407*ad7fcbc3SSagar Dharia 408*ad7fcbc3SSagar Dharia ctrl->rx.head = (ctrl->rx.head + 1) % ctrl->rx.n; 409*ad7fcbc3SSagar Dharia spin_unlock_irqrestore(&ctrl->rx.lock, flags); 410*ad7fcbc3SSagar Dharia 411*ad7fcbc3SSagar Dharia return 0; 412*ad7fcbc3SSagar Dharia } 413*ad7fcbc3SSagar Dharia 414*ad7fcbc3SSagar Dharia static void qcom_slim_rxwq(struct work_struct *work) 415*ad7fcbc3SSagar Dharia { 416*ad7fcbc3SSagar Dharia u8 buf[SLIM_MSGQ_BUF_LEN]; 417*ad7fcbc3SSagar Dharia u8 mc, mt, len; 418*ad7fcbc3SSagar Dharia int ret; 419*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl = container_of(work, struct qcom_slim_ctrl, 420*ad7fcbc3SSagar Dharia wd); 421*ad7fcbc3SSagar Dharia 422*ad7fcbc3SSagar Dharia while ((slim_get_current_rxbuf(ctrl, buf)) != -ENODATA) { 423*ad7fcbc3SSagar Dharia len = SLIM_HEADER_GET_RL(buf[0]); 424*ad7fcbc3SSagar Dharia mt = SLIM_HEADER_GET_MT(buf[0]); 425*ad7fcbc3SSagar Dharia mc = SLIM_HEADER_GET_MC(buf[1]); 426*ad7fcbc3SSagar Dharia if (mt == SLIM_MSG_MT_CORE && 427*ad7fcbc3SSagar Dharia mc == SLIM_MSG_MC_REPORT_PRESENT) { 428*ad7fcbc3SSagar Dharia struct slim_eaddr ea; 429*ad7fcbc3SSagar Dharia u8 laddr; 430*ad7fcbc3SSagar Dharia 431*ad7fcbc3SSagar Dharia ea.manf_id = be16_to_cpup((__be16 *)&buf[2]); 432*ad7fcbc3SSagar Dharia ea.prod_code = be16_to_cpup((__be16 *)&buf[4]); 433*ad7fcbc3SSagar Dharia ea.dev_index = buf[6]; 434*ad7fcbc3SSagar Dharia ea.instance = buf[7]; 435*ad7fcbc3SSagar Dharia 436*ad7fcbc3SSagar Dharia ret = slim_device_report_present(&ctrl->ctrl, &ea, 437*ad7fcbc3SSagar Dharia &laddr); 438*ad7fcbc3SSagar Dharia if (ret < 0) 439*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "assign laddr failed:%d\n", 440*ad7fcbc3SSagar Dharia ret); 441*ad7fcbc3SSagar Dharia } else { 442*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "unexpected message:mc:%x, mt:%x\n", 443*ad7fcbc3SSagar Dharia mc, mt); 444*ad7fcbc3SSagar Dharia } 445*ad7fcbc3SSagar Dharia } 446*ad7fcbc3SSagar Dharia } 447*ad7fcbc3SSagar Dharia 448*ad7fcbc3SSagar Dharia static void qcom_slim_prg_slew(struct platform_device *pdev, 449*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl) 450*ad7fcbc3SSagar Dharia { 451*ad7fcbc3SSagar Dharia struct resource *slew_mem; 452*ad7fcbc3SSagar Dharia 453*ad7fcbc3SSagar Dharia if (!ctrl->slew_reg) { 454*ad7fcbc3SSagar Dharia /* SLEW RATE register for this SLIMbus */ 455*ad7fcbc3SSagar Dharia slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, 456*ad7fcbc3SSagar Dharia "slew"); 457*ad7fcbc3SSagar Dharia ctrl->slew_reg = devm_ioremap(&pdev->dev, slew_mem->start, 458*ad7fcbc3SSagar Dharia resource_size(slew_mem)); 459*ad7fcbc3SSagar Dharia if (!ctrl->slew_reg) 460*ad7fcbc3SSagar Dharia return; 461*ad7fcbc3SSagar Dharia } 462*ad7fcbc3SSagar Dharia 463*ad7fcbc3SSagar Dharia writel_relaxed(1, ctrl->slew_reg); 464*ad7fcbc3SSagar Dharia /* Make sure SLIMbus-slew rate enabling goes through */ 465*ad7fcbc3SSagar Dharia wmb(); 466*ad7fcbc3SSagar Dharia } 467*ad7fcbc3SSagar Dharia 468*ad7fcbc3SSagar Dharia static int qcom_slim_probe(struct platform_device *pdev) 469*ad7fcbc3SSagar Dharia { 470*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl; 471*ad7fcbc3SSagar Dharia struct slim_controller *sctrl; 472*ad7fcbc3SSagar Dharia struct resource *slim_mem; 473*ad7fcbc3SSagar Dharia int ret, ver; 474*ad7fcbc3SSagar Dharia 475*ad7fcbc3SSagar Dharia ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 476*ad7fcbc3SSagar Dharia if (!ctrl) 477*ad7fcbc3SSagar Dharia return -ENOMEM; 478*ad7fcbc3SSagar Dharia 479*ad7fcbc3SSagar Dharia ctrl->hclk = devm_clk_get(&pdev->dev, "iface"); 480*ad7fcbc3SSagar Dharia if (IS_ERR(ctrl->hclk)) 481*ad7fcbc3SSagar Dharia return PTR_ERR(ctrl->hclk); 482*ad7fcbc3SSagar Dharia 483*ad7fcbc3SSagar Dharia ctrl->rclk = devm_clk_get(&pdev->dev, "core"); 484*ad7fcbc3SSagar Dharia if (IS_ERR(ctrl->rclk)) 485*ad7fcbc3SSagar Dharia return PTR_ERR(ctrl->rclk); 486*ad7fcbc3SSagar Dharia 487*ad7fcbc3SSagar Dharia ret = clk_set_rate(ctrl->rclk, SLIM_ROOT_FREQ); 488*ad7fcbc3SSagar Dharia if (ret) { 489*ad7fcbc3SSagar Dharia dev_err(&pdev->dev, "ref-clock set-rate failed:%d\n", ret); 490*ad7fcbc3SSagar Dharia return ret; 491*ad7fcbc3SSagar Dharia } 492*ad7fcbc3SSagar Dharia 493*ad7fcbc3SSagar Dharia ctrl->irq = platform_get_irq(pdev, 0); 494*ad7fcbc3SSagar Dharia if (!ctrl->irq) { 495*ad7fcbc3SSagar Dharia dev_err(&pdev->dev, "no slimbus IRQ\n"); 496*ad7fcbc3SSagar Dharia return -ENODEV; 497*ad7fcbc3SSagar Dharia } 498*ad7fcbc3SSagar Dharia 499*ad7fcbc3SSagar Dharia sctrl = &ctrl->ctrl; 500*ad7fcbc3SSagar Dharia sctrl->dev = &pdev->dev; 501*ad7fcbc3SSagar Dharia ctrl->dev = &pdev->dev; 502*ad7fcbc3SSagar Dharia platform_set_drvdata(pdev, ctrl); 503*ad7fcbc3SSagar Dharia dev_set_drvdata(ctrl->dev, ctrl); 504*ad7fcbc3SSagar Dharia 505*ad7fcbc3SSagar Dharia slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); 506*ad7fcbc3SSagar Dharia ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem); 507*ad7fcbc3SSagar Dharia if (!ctrl->base) { 508*ad7fcbc3SSagar Dharia dev_err(&pdev->dev, "IOremap failed\n"); 509*ad7fcbc3SSagar Dharia return -ENOMEM; 510*ad7fcbc3SSagar Dharia } 511*ad7fcbc3SSagar Dharia 512*ad7fcbc3SSagar Dharia sctrl->set_laddr = qcom_set_laddr; 513*ad7fcbc3SSagar Dharia sctrl->xfer_msg = qcom_xfer_msg; 514*ad7fcbc3SSagar Dharia ctrl->tx.n = QCOM_TX_MSGS; 515*ad7fcbc3SSagar Dharia ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN; 516*ad7fcbc3SSagar Dharia ctrl->rx.n = QCOM_RX_MSGS; 517*ad7fcbc3SSagar Dharia ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN; 518*ad7fcbc3SSagar Dharia ctrl->wr_comp = kzalloc(sizeof(struct completion *) * QCOM_TX_MSGS, 519*ad7fcbc3SSagar Dharia GFP_KERNEL); 520*ad7fcbc3SSagar Dharia if (!ctrl->wr_comp) 521*ad7fcbc3SSagar Dharia return -ENOMEM; 522*ad7fcbc3SSagar Dharia 523*ad7fcbc3SSagar Dharia spin_lock_init(&ctrl->rx.lock); 524*ad7fcbc3SSagar Dharia spin_lock_init(&ctrl->tx.lock); 525*ad7fcbc3SSagar Dharia INIT_WORK(&ctrl->wd, qcom_slim_rxwq); 526*ad7fcbc3SSagar Dharia ctrl->rxwq = create_singlethread_workqueue("qcom_slim_rx"); 527*ad7fcbc3SSagar Dharia if (!ctrl->rxwq) { 528*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "Failed to start Rx WQ\n"); 529*ad7fcbc3SSagar Dharia return -ENOMEM; 530*ad7fcbc3SSagar Dharia } 531*ad7fcbc3SSagar Dharia 532*ad7fcbc3SSagar Dharia ctrl->framer.rootfreq = SLIM_ROOT_FREQ / 8; 533*ad7fcbc3SSagar Dharia ctrl->framer.superfreq = 534*ad7fcbc3SSagar Dharia ctrl->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8; 535*ad7fcbc3SSagar Dharia sctrl->a_framer = &ctrl->framer; 536*ad7fcbc3SSagar Dharia sctrl->clkgear = SLIM_MAX_CLK_GEAR; 537*ad7fcbc3SSagar Dharia 538*ad7fcbc3SSagar Dharia qcom_slim_prg_slew(pdev, ctrl); 539*ad7fcbc3SSagar Dharia 540*ad7fcbc3SSagar Dharia ret = devm_request_irq(&pdev->dev, ctrl->irq, qcom_slim_interrupt, 541*ad7fcbc3SSagar Dharia IRQF_TRIGGER_HIGH, "qcom_slim_irq", ctrl); 542*ad7fcbc3SSagar Dharia if (ret) { 543*ad7fcbc3SSagar Dharia dev_err(&pdev->dev, "request IRQ failed\n"); 544*ad7fcbc3SSagar Dharia goto err_request_irq_failed; 545*ad7fcbc3SSagar Dharia } 546*ad7fcbc3SSagar Dharia 547*ad7fcbc3SSagar Dharia ret = clk_prepare_enable(ctrl->hclk); 548*ad7fcbc3SSagar Dharia if (ret) 549*ad7fcbc3SSagar Dharia goto err_hclk_enable_failed; 550*ad7fcbc3SSagar Dharia 551*ad7fcbc3SSagar Dharia ret = clk_prepare_enable(ctrl->rclk); 552*ad7fcbc3SSagar Dharia if (ret) 553*ad7fcbc3SSagar Dharia goto err_rclk_enable_failed; 554*ad7fcbc3SSagar Dharia 555*ad7fcbc3SSagar Dharia ctrl->tx.base = dmam_alloc_coherent(&pdev->dev, 556*ad7fcbc3SSagar Dharia (ctrl->tx.sl_sz * ctrl->tx.n), 557*ad7fcbc3SSagar Dharia &ctrl->tx.phy, GFP_KERNEL); 558*ad7fcbc3SSagar Dharia if (!ctrl->tx.base) { 559*ad7fcbc3SSagar Dharia ret = -ENOMEM; 560*ad7fcbc3SSagar Dharia goto err; 561*ad7fcbc3SSagar Dharia } 562*ad7fcbc3SSagar Dharia 563*ad7fcbc3SSagar Dharia ctrl->rx.base = dmam_alloc_coherent(&pdev->dev, 564*ad7fcbc3SSagar Dharia (ctrl->rx.sl_sz * ctrl->rx.n), 565*ad7fcbc3SSagar Dharia &ctrl->rx.phy, GFP_KERNEL); 566*ad7fcbc3SSagar Dharia if (!ctrl->rx.base) { 567*ad7fcbc3SSagar Dharia ret = -ENOMEM; 568*ad7fcbc3SSagar Dharia goto err; 569*ad7fcbc3SSagar Dharia } 570*ad7fcbc3SSagar Dharia 571*ad7fcbc3SSagar Dharia /* Register with framework before enabling frame, clock */ 572*ad7fcbc3SSagar Dharia ret = slim_register_controller(&ctrl->ctrl); 573*ad7fcbc3SSagar Dharia if (ret) { 574*ad7fcbc3SSagar Dharia dev_err(ctrl->dev, "error adding controller\n"); 575*ad7fcbc3SSagar Dharia goto err; 576*ad7fcbc3SSagar Dharia } 577*ad7fcbc3SSagar Dharia 578*ad7fcbc3SSagar Dharia ver = readl_relaxed(ctrl->base); 579*ad7fcbc3SSagar Dharia /* Version info in 16 MSbits */ 580*ad7fcbc3SSagar Dharia ver >>= 16; 581*ad7fcbc3SSagar Dharia /* Component register initialization */ 582*ad7fcbc3SSagar Dharia writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver)); 583*ad7fcbc3SSagar Dharia writel((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1), 584*ad7fcbc3SSagar Dharia ctrl->base + CFG_PORT(COMP_TRUST_CFG, ver)); 585*ad7fcbc3SSagar Dharia 586*ad7fcbc3SSagar Dharia writel((MGR_INT_TX_NACKED_2 | 587*ad7fcbc3SSagar Dharia MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD | 588*ad7fcbc3SSagar Dharia MGR_INT_TX_MSG_SENT), ctrl->base + MGR_INT_EN); 589*ad7fcbc3SSagar Dharia writel(1, ctrl->base + MGR_CFG); 590*ad7fcbc3SSagar Dharia /* Framer register initialization */ 591*ad7fcbc3SSagar Dharia writel((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) | 592*ad7fcbc3SSagar Dharia (0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1, 593*ad7fcbc3SSagar Dharia ctrl->base + FRM_CFG); 594*ad7fcbc3SSagar Dharia writel(MGR_CFG_ENABLE, ctrl->base + MGR_CFG); 595*ad7fcbc3SSagar Dharia writel(1, ctrl->base + INTF_CFG); 596*ad7fcbc3SSagar Dharia writel(1, ctrl->base + CFG_PORT(COMP_CFG, ver)); 597*ad7fcbc3SSagar Dharia 598*ad7fcbc3SSagar Dharia pm_runtime_use_autosuspend(&pdev->dev); 599*ad7fcbc3SSagar Dharia pm_runtime_set_autosuspend_delay(&pdev->dev, QCOM_SLIM_AUTOSUSPEND); 600*ad7fcbc3SSagar Dharia pm_runtime_set_active(&pdev->dev); 601*ad7fcbc3SSagar Dharia pm_runtime_mark_last_busy(&pdev->dev); 602*ad7fcbc3SSagar Dharia pm_runtime_enable(&pdev->dev); 603*ad7fcbc3SSagar Dharia 604*ad7fcbc3SSagar Dharia dev_dbg(ctrl->dev, "QCOM SB controller is up:ver:0x%x!\n", ver); 605*ad7fcbc3SSagar Dharia return 0; 606*ad7fcbc3SSagar Dharia 607*ad7fcbc3SSagar Dharia err: 608*ad7fcbc3SSagar Dharia clk_disable_unprepare(ctrl->rclk); 609*ad7fcbc3SSagar Dharia err_rclk_enable_failed: 610*ad7fcbc3SSagar Dharia clk_disable_unprepare(ctrl->hclk); 611*ad7fcbc3SSagar Dharia err_hclk_enable_failed: 612*ad7fcbc3SSagar Dharia err_request_irq_failed: 613*ad7fcbc3SSagar Dharia destroy_workqueue(ctrl->rxwq); 614*ad7fcbc3SSagar Dharia return ret; 615*ad7fcbc3SSagar Dharia } 616*ad7fcbc3SSagar Dharia 617*ad7fcbc3SSagar Dharia static int qcom_slim_remove(struct platform_device *pdev) 618*ad7fcbc3SSagar Dharia { 619*ad7fcbc3SSagar Dharia struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev); 620*ad7fcbc3SSagar Dharia 621*ad7fcbc3SSagar Dharia disable_irq(ctrl->irq); 622*ad7fcbc3SSagar Dharia clk_disable_unprepare(ctrl->hclk); 623*ad7fcbc3SSagar Dharia clk_disable_unprepare(ctrl->rclk); 624*ad7fcbc3SSagar Dharia slim_unregister_controller(&ctrl->ctrl); 625*ad7fcbc3SSagar Dharia destroy_workqueue(ctrl->rxwq); 626*ad7fcbc3SSagar Dharia return 0; 627*ad7fcbc3SSagar Dharia } 628*ad7fcbc3SSagar Dharia 629*ad7fcbc3SSagar Dharia static const struct dev_pm_ops qcom_slim_dev_pm_ops = { 630*ad7fcbc3SSagar Dharia SET_SYSTEM_SLEEP_PM_OPS(qcom_slim_suspend, qcom_slim_resume) 631*ad7fcbc3SSagar Dharia SET_RUNTIME_PM_OPS( 632*ad7fcbc3SSagar Dharia qcom_slim_runtime_suspend, 633*ad7fcbc3SSagar Dharia qcom_slim_runtime_resume, 634*ad7fcbc3SSagar Dharia NULL 635*ad7fcbc3SSagar Dharia ) 636*ad7fcbc3SSagar Dharia }; 637*ad7fcbc3SSagar Dharia 638*ad7fcbc3SSagar Dharia static const struct of_device_id qcom_slim_dt_match[] = { 639*ad7fcbc3SSagar Dharia { .compatible = "qcom,slim", }, 640*ad7fcbc3SSagar Dharia { .compatible = "qcom,apq8064-slim", }, 641*ad7fcbc3SSagar Dharia {} 642*ad7fcbc3SSagar Dharia }; 643*ad7fcbc3SSagar Dharia 644*ad7fcbc3SSagar Dharia static struct platform_driver qcom_slim_driver = { 645*ad7fcbc3SSagar Dharia .probe = qcom_slim_probe, 646*ad7fcbc3SSagar Dharia .remove = qcom_slim_remove, 647*ad7fcbc3SSagar Dharia .driver = { 648*ad7fcbc3SSagar Dharia .name = "qcom_slim_ctrl", 649*ad7fcbc3SSagar Dharia .of_match_table = qcom_slim_dt_match, 650*ad7fcbc3SSagar Dharia }, 651*ad7fcbc3SSagar Dharia }; 652*ad7fcbc3SSagar Dharia module_platform_driver(qcom_slim_driver); 653*ad7fcbc3SSagar Dharia 654*ad7fcbc3SSagar Dharia MODULE_LICENSE("GPL v2"); 655*ad7fcbc3SSagar Dharia MODULE_DESCRIPTION("Qualcomm SLIMbus Controller"); 656