blob: 78e8a6f5c7aaf2f686a19bc6ffc0b2651dc38f85 [file] [log] [blame]
Sagar Dhariab47c8962012-10-30 13:44:08 -06001/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Sagar Dharia71fcea52012-09-12 23:21:57 -06002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/irq.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/io.h>
18#include <linux/interrupt.h>
19#include <linux/platform_device.h>
20#include <linux/dma-mapping.h>
21#include <linux/slimbus/slimbus.h>
22#include <linux/delay.h>
23#include <linux/kthread.h>
24#include <linux/clk.h>
25#include <linux/pm_runtime.h>
26#include <linux/of.h>
27#include <linux/of_slimbus.h>
28#include <linux/timer.h>
29#include <mach/sps.h>
30#include "slim-msm.h"
31#include <mach/qdsp6v2/apr.h>
32
33#define NGD_SLIM_NAME "ngd_msm_ctrl"
34#define SLIM_LA_MGR 0xFF
35#define SLIM_ROOT_FREQ 24576000
36
37#define NGD_BASE_V1(r) (((r) % 2) ? 0x800 : 0xA00)
38#define NGD_BASE_V2(r) (((r) % 2) ? 0x1000 : 0x2000)
39#define NGD_BASE(r, v) ((v) ? NGD_BASE_V2(r) : NGD_BASE_V1(r))
40/* NGD (Non-ported Generic Device) registers */
41enum ngd_reg {
42 NGD_CFG = 0x0,
43 NGD_STATUS = 0x4,
44 NGD_RX_MSGQ_CFG = 0x8,
45 NGD_INT_EN = 0x10,
46 NGD_INT_STAT = 0x14,
47 NGD_INT_CLR = 0x18,
48 NGD_TX_MSG = 0x30,
49 NGD_RX_MSG = 0x70,
50 NGD_IE_STAT = 0xF0,
51 NGD_VE_STAT = 0x100,
52};
53
54enum ngd_msg_cfg {
55 NGD_CFG_ENABLE = 1,
56 NGD_CFG_RX_MSGQ_EN = 1 << 1,
57 NGD_CFG_TX_MSGQ_EN = 1 << 2,
58};
59
60enum ngd_intr {
61 NGD_INT_RECFG_DONE = 1 << 24,
62 NGD_INT_TX_NACKED_2 = 1 << 25,
63 NGD_INT_MSG_BUF_CONTE = 1 << 26,
64 NGD_INT_MSG_TX_INVAL = 1 << 27,
65 NGD_INT_IE_VE_CHG = 1 << 28,
66 NGD_INT_DEV_ERR = 1 << 29,
67 NGD_INT_RX_MSG_RCVD = 1 << 30,
68 NGD_INT_TX_MSG_SENT = 1 << 31,
69};
70
71enum ngd_offsets {
72 NGD_NACKED_MC = 0x7F00000,
73 NGD_ACKED_MC = 0xFE000,
74 NGD_ERROR = 0x1800,
75 NGD_MSGQ_SUPPORT = 0x400,
76 NGD_RX_MSGQ_TIME_OUT = 0x16,
77 NGD_ENUMERATED = 0x1,
78 NGD_TX_BUSY = 0x0,
79};
80
81static irqreturn_t ngd_slim_interrupt(int irq, void *d)
82{
83 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
84 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
85 u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
86
87 if (stat & NGD_INT_TX_MSG_SENT) {
88 writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
89 /* Make sure interrupt is cleared */
90 mb();
91 if (dev->wr_comp)
92 complete(dev->wr_comp);
93 } else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
94 (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
95 (stat & NGD_INT_TX_NACKED_2)) {
96 dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
97 writel_relaxed(stat, ngd + NGD_INT_CLR);
98 /* Guarantee that error interrupts are cleared */
99 mb();
100 if (((stat & NGD_INT_TX_NACKED_2) ||
101 (stat & NGD_INT_MSG_TX_INVAL))) {
102 dev->err = -EIO;
103 if (dev->wr_comp)
104 complete(dev->wr_comp);
105 }
106 }
107 if (stat & NGD_INT_RX_MSG_RCVD) {
108 u32 rx_buf[10];
109 u8 len, i;
110 rx_buf[0] = readl_relaxed(ngd + NGD_RX_MSG);
111 len = rx_buf[0] & 0x1F;
112 for (i = 1; i < ((len + 3) >> 2); i++) {
113 rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
114 (4 * i));
115 dev_dbg(dev->dev, "REG-RX data: %x\n", rx_buf[i]);
116 }
117 msm_slim_rx_enqueue(dev, rx_buf, len);
118 writel_relaxed(NGD_INT_RX_MSG_RCVD,
119 ngd + NGD_INT_CLR);
120 /*
121 * Guarantee that CLR bit write goes through before
122 * queuing work
123 */
124 mb();
125 if (dev->use_rx_msgqs)
126 dev_err(dev->dev,
127 "direct message received even with RX MSGQs");
128 else
129 complete(&dev->rx_msgq_notify);
130 }
131 if (stat & NGD_INT_RECFG_DONE) {
132 writel_relaxed(NGD_INT_RECFG_DONE, ngd + NGD_INT_CLR);
133 /* Guarantee RECONFIG DONE interrupt is cleared */
134 mb();
135 /* In satellite mode, just log the reconfig done IRQ */
136 dev_dbg(dev->dev, "reconfig done IRQ for NGD");
137 }
138 if (stat & NGD_INT_IE_VE_CHG) {
139 writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
140 /* Guarantee IE VE change interrupt is cleared */
141 mb();
142 dev_err(dev->dev, "NGD IE VE change");
143 }
144 return IRQ_HANDLED;
145}
146
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700147static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
148{
149 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
150 return msm_slim_qmi_power_request(dev, true);
151}
152
153static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
154 void *_cmd)
155{
156 struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
157 pr_info("Slimbus QMI NGD CB received event:%ld", code);
158 switch (code) {
159 case QMI_SERVER_ARRIVE:
160 complete(&qmi->qmi_comp);
161 break;
162 case QMI_SERVER_EXIT:
163 /* SSR implementation */
164 break;
165 default:
166 break;
167 }
168 return 0;
169}
170
Sagar Dharia71fcea52012-09-12 23:21:57 -0600171static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
172 u8 *tid, struct completion *done)
173{
174 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariad2959352012-12-01 15:43:01 -0700175 mutex_lock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600176 if (ctrl->last_tid <= 255) {
177 ctrl->txnt = krealloc(ctrl->txnt,
178 (ctrl->last_tid + 1) *
179 sizeof(struct slim_msg_txn *),
180 GFP_KERNEL);
Sagar Dhariad2959352012-12-01 15:43:01 -0700181 if (!ctrl->txnt) {
182 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600183 return -ENOMEM;
Sagar Dhariad2959352012-12-01 15:43:01 -0700184 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600185 dev->msg_cnt = ctrl->last_tid;
186 ctrl->last_tid++;
187 } else {
188 int i;
189 for (i = 0; i < 256; i++) {
190 dev->msg_cnt = ((dev->msg_cnt + 1) & 0xFF);
191 if (ctrl->txnt[dev->msg_cnt] == NULL)
192 break;
193 }
194 if (i >= 256) {
195 dev_err(&ctrl->dev, "out of TID");
Sagar Dhariad2959352012-12-01 15:43:01 -0700196 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600197 return -ENOMEM;
198 }
199 }
200 ctrl->txnt[dev->msg_cnt] = txn;
201 txn->tid = dev->msg_cnt;
202 txn->comp = done;
203 *tid = dev->msg_cnt;
Sagar Dhariad2959352012-12-01 15:43:01 -0700204 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600205 return 0;
206}
207static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
208{
209 DECLARE_COMPLETION_ONSTACK(done);
210 DECLARE_COMPLETION_ONSTACK(tx_sent);
211
212 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
213 u32 *pbuf;
214 u8 *puc;
215 int ret = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600216 u8 la = txn->la;
217 u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
218
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700219 if (txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
220 SLIM_MSG_MC_RECONFIGURE_NOW))
221 return msm_slim_qmi_power_request(dev, false);
222 else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
223 return 0;
224
Sagar Dharia71fcea52012-09-12 23:21:57 -0600225 if (txn->mt == SLIM_MSG_MT_CORE &&
226 (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
227 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
228 return 0;
229 }
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700230 msm_slim_get_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600231 mutex_lock(&dev->tx_lock);
232 if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
233 (dev->state == MSM_CTRL_ASLEEP ||
234 dev->state == MSM_CTRL_SLEEPING)) {
235 int timeout;
236 dev_err(dev->dev, "controller not ready");
237 mutex_unlock(&dev->tx_lock);
238 /* Reconf is signalled when master responds */
239 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
240 if (timeout) {
241 mutex_lock(&dev->tx_lock);
242 } else {
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700243 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600244 return -EBUSY;
245 }
246 }
247 if (txn->mt == SLIM_MSG_MT_CORE &&
248 (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
249 txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
250 txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
251 int i = 0;
252 txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
253 if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
254 txn->mc = SLIM_USR_MC_CONNECT_SRC;
255 else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
256 txn->mc = SLIM_USR_MC_CONNECT_SINK;
257 else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
258 txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
259 if (txn->la == SLIM_LA_MGR)
260 txn->la = dev->pgdla;
261 wbuf[i++] = txn->la;
262 la = SLIM_LA_MGR;
263 wbuf[i++] = txn->wbuf[0];
264 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
265 wbuf[i++] = txn->wbuf[1];
266 ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
267 if (ret) {
268 pr_err("TID for connect/disconnect fail:%d", ret);
269 goto ngd_xfer_err;
270 }
271 txn->len = i;
272 txn->wbuf = wbuf;
273 txn->rl = txn->len + 4;
274 }
275 txn->rl--;
276 pbuf = msm_get_msg_buf(dev, txn->rl);
277 if (!pbuf) {
278 dev_err(dev->dev, "Message buffer unavailable");
279 ret = -ENOMEM;
280 goto ngd_xfer_err;
281 }
282 dev->err = 0;
283
284 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
285 ret = -EPROTONOSUPPORT;
286 goto ngd_xfer_err;
287 }
288 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
289 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
290 la);
291 else
292 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
293 la);
294 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
295 puc = ((u8 *)pbuf) + 3;
296 else
297 puc = ((u8 *)pbuf) + 2;
298 if (txn->rbuf)
299 *(puc++) = txn->tid;
300 if ((txn->mt == SLIM_MSG_MT_CORE) &&
301 ((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
302 txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
303 (txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
304 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
305 *(puc++) = (txn->ec & 0xFF);
306 *(puc++) = (txn->ec >> 8)&0xFF;
307 }
308 if (txn->wbuf)
309 memcpy(puc, txn->wbuf, txn->len);
310 if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
311 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
312 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
313 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
314 wbuf[0] == dev->pgdla) {
315 if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
316 dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
317 else {
318 struct msm_slim_endp *endpoint = &dev->pipes[wbuf[1]];
319 struct sps_register_event sps_event;
320 memset(&sps_event, 0, sizeof(sps_event));
321 sps_register_event(endpoint->sps, &sps_event);
322 sps_disconnect(endpoint->sps);
323 /*
324 * Remove channel disconnects master-side ports from
325 * channel. No need to send that again on the bus
326 */
327 dev->pipes[wbuf[1]].connected = false;
328 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700329 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600330 return 0;
331 }
332 if (dev->err) {
333 dev_err(dev->dev, "pipe-port connect err:%d", dev->err);
334 goto ngd_xfer_err;
335 }
336 }
337 dev->err = 0;
338 dev->wr_comp = &tx_sent;
339 ret = msm_send_msg_buf(dev, pbuf, txn->rl,
340 NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
341 if (!ret) {
342 int timeout = wait_for_completion_timeout(&tx_sent, HZ);
343 if (!timeout)
344 ret = -ETIMEDOUT;
345 else
346 ret = dev->err;
347 }
348 dev->wr_comp = NULL;
349 if (ret) {
350 u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
351 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
352 dev->ver);
353 dev_err(dev->dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d",
354 txn->mc, txn->mt, ret, dev->ver);
355 conf = readl_relaxed(ngd);
356 stat = readl_relaxed(ngd + NGD_STATUS);
357 rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
358 int_stat = readl_relaxed(ngd + NGD_INT_STAT);
359 int_en = readl_relaxed(ngd + NGD_INT_EN);
360 int_clr = readl_relaxed(ngd + NGD_INT_CLR);
361
362 pr_err("conf:0x%x,stat:0x%x,rxmsgq:0x%x", conf, stat, rx_msgq);
363 pr_err("int_stat:0x%x,int_en:0x%x,int_cll:0x%x", int_stat,
364 int_en, int_clr);
365 } else if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
366 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
367 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
368 txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
369 int timeout;
370 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700371 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600372 timeout = wait_for_completion_timeout(txn->comp, HZ);
373 if (!timeout) {
374 pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
375 txn->tid);
376 ret = -ETIMEDOUT;
Sagar Dhariad2959352012-12-01 15:43:01 -0700377 mutex_lock(&ctrl->m_ctrl);
378 ctrl->txnt[txn->tid] = NULL;
379 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600380 } else {
381 ret = txn->ec;
382 }
383 if (ret)
384 pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
385 txn->tid, ret);
386 return ret ? ret : dev->err;
387 }
388ngd_xfer_err:
389 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700390 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600391 return ret ? ret : dev->err;
392}
393
394static int ngd_xferandwait_ack(struct slim_controller *ctrl,
395 struct slim_msg_txn *txn)
396{
397 int ret = ngd_xfer_msg(ctrl, txn);
398 if (!ret) {
399 int timeout;
400 timeout = wait_for_completion_timeout(txn->comp, HZ);
401 if (!timeout) {
402 pr_err("master req:0x%x, tid:%d timed out", txn->mc,
403 txn->tid);
404 ret = -ETIMEDOUT;
Sagar Dhariad2959352012-12-01 15:43:01 -0700405 mutex_lock(&ctrl->m_ctrl);
406 ctrl->txnt[txn->tid] = NULL;
407 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600408 } else {
409 ret = txn->ec;
410 }
411 }
412 if (ret)
413 pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
414 txn->tid, ret);
415
416 return ret;
417}
418
419static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
420{
421 int ret;
422 struct slim_pending_ch *pch;
423 struct slim_msg_txn txn;
424 struct slim_controller *ctrl = sb->ctrl;
425 DECLARE_COMPLETION_ONSTACK(done);
426 u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
427
428 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
429 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
430 txn.la = SLIM_LA_MGR;
431 txn.len = 0;
432 txn.ec = 0;
433 txn.wbuf = wbuf;
434 txn.rbuf = NULL;
435
436 list_for_each_entry(pch, &sb->mark_define, pending) {
437 struct slim_ich *slc;
438 slc = &ctrl->chans[pch->chan];
439 if (!slc) {
440 pr_err("no channel in define?");
441 return -ENXIO;
442 }
443 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600444 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600445 wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600446 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600447 wbuf[txn.len] = slc->seglen;
448 if (slc->coeff == SLIM_COEFF_3)
449 wbuf[txn.len] |= 1 << 5;
450 wbuf[txn.len++] |= slc->prop.auxf << 6;
451 wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
452 wbuf[txn.len++] = slc->prrate;
453 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
454 if (ret) {
455 pr_err("no tid for channel define?");
456 return -ENXIO;
457 }
458 }
459 wbuf[txn.len++] = slc->chan;
Sagar Dhariab47c8962012-10-30 13:44:08 -0600460 pr_debug("slim define chan:%d, tid:0x%x", slc->chan, txn.tid);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600461 }
462 if (txn.len) {
463 txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
464 txn.rl = txn.len + 4;
465 ret = ngd_xferandwait_ack(ctrl, &txn);
466 if (ret)
467 return ret;
468
469 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
470 txn.len = 2;
471 wbuf[1] = sb->laddr;
472 txn.rl = txn.len + 4;
473 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
474 if (ret)
475 return ret;
476 ret = ngd_xferandwait_ack(ctrl, &txn);
477 if (ret)
478 return ret;
479 }
480 txn.len = 0;
481 list_for_each_entry(pch, &sb->mark_removal, pending) {
482 struct slim_ich *slc;
483 slc = &ctrl->chans[pch->chan];
484 if (!slc) {
485 pr_err("no channel in removal?");
486 return -ENXIO;
487 }
488 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600489 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600490 wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600491 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600492 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
493 if (ret) {
494 pr_err("no tid for channel define?");
495 return -ENXIO;
496 }
497 }
498 wbuf[txn.len++] = slc->chan;
Sagar Dhariab47c8962012-10-30 13:44:08 -0600499 pr_debug("slim remove chan:%d, tid:0x%x", slc->chan, txn.tid);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600500 }
501 if (txn.len) {
502 txn.mc = SLIM_USR_MC_CHAN_CTRL;
503 txn.rl = txn.len + 4;
504 ret = ngd_xferandwait_ack(ctrl, &txn);
505 if (ret)
506 return ret;
507
508 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
509 txn.len = 2;
510 wbuf[1] = sb->laddr;
511 txn.rl = txn.len + 4;
512 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
513 if (ret)
514 return ret;
515 ret = ngd_xferandwait_ack(ctrl, &txn);
516 if (ret)
517 return ret;
518 txn.len = 0;
519 }
520 return ret;
521}
522
523static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
524 u8 elen, u8 laddr)
525{
526 return 0;
527}
528
529static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
530 u8 elen, u8 *laddr)
531{
532 int ret;
533 u8 wbuf[10];
534 struct slim_msg_txn txn;
535 DECLARE_COMPLETION_ONSTACK(done);
536 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
537 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
538 txn.la = SLIM_LA_MGR;
539 txn.ec = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600540 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
541 if (ret) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600542 return ret;
543 }
544 memcpy(&wbuf[1], ea, elen);
545 txn.mc = SLIM_USR_MC_ADDR_QUERY;
546 txn.rl = 11;
547 txn.len = 7;
548 txn.wbuf = wbuf;
549 txn.rbuf = NULL;
550 ret = ngd_xferandwait_ack(ctrl, &txn);
551 if (!ret && txn.la == 0xFF)
552 ret = -ENXIO;
553 else if (!ret)
554 *laddr = txn.la;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600555 return ret;
556}
557
558static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
559{
560 u8 mc, mt, len;
561 int ret;
562 u32 msgq_en = 1;
563
564 len = buf[0] & 0x1F;
565 mt = (buf[0] >> 5) & 0x7;
566 mc = buf[1];
567 if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
568 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
569 struct slim_msg_txn txn;
570 u8 wbuf[8];
571 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
572 txn.ec = 0;
573 txn.rbuf = NULL;
574 txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
575 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
576 txn.la = SLIM_LA_MGR;
577 txn.rl = 8;
578 wbuf[0] = SAT_MAGIC_LSB;
579 wbuf[1] = SAT_MAGIC_MSB;
580 wbuf[2] = SAT_MSG_VER;
581 wbuf[3] = SAT_MSG_PROT;
582 txn.wbuf = wbuf;
583 txn.len = 4;
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700584 pr_info("SLIM SAT: Received master capability");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600585 dev->use_rx_msgqs = 1;
586 msm_slim_sps_init(dev, dev->bam_mem,
587 NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
588 if (dev->use_rx_msgqs)
589 msgq_en |= NGD_CFG_RX_MSGQ_EN;
590 writel_relaxed(msgq_en, dev->base +
591 NGD_BASE(dev->ctrl.nr, dev->ver));
592 /* make sure NGD MSG-Q config goes through */
593 mb();
594
595 ret = ngd_xfer_msg(&dev->ctrl, &txn);
596 if (!ret) {
597 dev->state = MSM_CTRL_AWAKE;
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700598
599 pm_runtime_use_autosuspend(dev->dev);
600 pm_runtime_set_autosuspend_delay(dev->dev,
601 MSM_SLIM_AUTOSUSPEND);
602 pm_runtime_set_active(dev->dev);
603 pm_runtime_enable(dev->dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600604 complete(&dev->reconf);
605 }
606 }
607 if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
608 mc == SLIM_MSG_MC_REPLY_VALUE) {
609 u8 tid = buf[3];
610 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
611 slim_msg_response(&dev->ctrl, &buf[4], tid,
612 len - 4);
613 pm_runtime_mark_last_busy(dev->dev);
614 }
615 if (mc == SLIM_USR_MC_ADDR_REPLY &&
616 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700617 struct slim_msg_txn *txn;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600618 u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
Sagar Dhariad2959352012-12-01 15:43:01 -0700619 mutex_lock(&dev->ctrl.m_ctrl);
620 txn = dev->ctrl.txnt[buf[3]];
621 if (!txn) {
622 pr_err("LADDR response after timeout, tid:0x%x",
623 buf[3]);
624 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600625 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700626 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600627 if (memcmp(&buf[4], failed_ea, 6))
628 txn->la = buf[10];
629 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700630 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600631 complete(txn->comp);
632 }
633 if (mc == SLIM_USR_MC_GENERIC_ACK &&
634 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700635 struct slim_msg_txn *txn;
636 mutex_lock(&dev->ctrl.m_ctrl);
637 txn = dev->ctrl.txnt[buf[3]];
638 if (!txn) {
639 pr_err("ACK received after timeout, tid:0x%x",
640 buf[3]);
641 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600642 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700643 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600644 dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
645 (int)buf[3], buf[4]);
646 if (!(buf[4] & MSM_SAT_SUCCSS)) {
647 dev_err(dev->dev, "TID:%d, NACK code:0x%x", (int)buf[3],
648 buf[4]);
649 txn->ec = -EIO;
650 }
651 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700652 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600653 complete(txn->comp);
654 }
655}
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700656
657static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
658{
659 u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
660 NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
661 NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
662 NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
663 if (enable) {
664 int ret = msm_slim_qmi_init(dev, false);
665 if (ret)
666 return ret;
667 ret = msm_slim_qmi_power_request(dev, true);
668 if (ret)
669 return ret;
670 writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
671 NGD_BASE(dev->ctrl.nr, dev->ver));
672 /*
673 * Enable NGD. Configure NGD in register acc. mode until master
674 * announcement is received
675 */
676 writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
677 /* make sure NGD enabling goes through */
678 mb();
679 } else {
680 writel_relaxed(0, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
681 writel_relaxed(0, dev->base + NGD_INT_EN +
682 NGD_BASE(dev->ctrl.nr, dev->ver));
683 /* make sure NGD disabling goes through */
684 mb();
685 msm_slim_qmi_exit(dev);
686 }
687
688 return 0;
689}
690
Sagar Dharia71fcea52012-09-12 23:21:57 -0600691static int ngd_slim_rx_msgq_thread(void *data)
692{
693 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
694 struct completion *notify = &dev->rx_msgq_notify;
695 int ret = 0, index = 0;
696 u32 mc = 0;
697 u32 mt = 0;
698 u32 buffer[10];
699 u8 msg_len = 0;
700
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700701 wait_for_completion_interruptible(&dev->qmi.qmi_comp);
702 ret = ngd_slim_enable(dev, true);
703 /* Exit the thread if component can't be enabled */
704 if (ret) {
705 pr_err("Enabling NGD failed:%d", ret);
706 return 0;
707 }
708
Sagar Dharia71fcea52012-09-12 23:21:57 -0600709 while (!kthread_should_stop()) {
710 set_current_state(TASK_INTERRUPTIBLE);
711 ret = wait_for_completion_interruptible(notify);
712 if (ret) {
713 dev_err(dev->dev, "rx thread wait err:%d", ret);
714 continue;
715 }
716 /* 1 irq notification per message */
717 if (!dev->use_rx_msgqs) {
718 msm_slim_rx_dequeue(dev, (u8 *)buffer);
719 ngd_slim_rx(dev, (u8 *)buffer);
720 continue;
721 }
722 ret = msm_slim_rx_msgq_get(dev, buffer, index);
723 if (ret) {
724 dev_err(dev->dev, "rx_msgq_get() failed 0x%x\n", ret);
725 continue;
726 }
727
728 /* Wait for complete message */
729 if (index++ == 0) {
730 msg_len = *buffer & 0x1F;
731 mt = (buffer[0] >> 5) & 0x7;
732 mc = (buffer[0] >> 8) & 0xff;
733 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
734 }
735 if ((index * 4) >= msg_len) {
736 index = 0;
737 ngd_slim_rx(dev, (u8 *)buffer);
738 } else
739 continue;
740 }
741 return 0;
742}
743
744static int __devinit ngd_slim_probe(struct platform_device *pdev)
745{
746 struct msm_slim_ctrl *dev;
747 int ret;
748 struct resource *bam_mem;
749 struct resource *slim_mem;
750 struct resource *irq, *bam_irq;
751 enum apr_subsys_state q6_state;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600752
753 q6_state = apr_get_q6_state();
754 if (q6_state == APR_SUBSYS_DOWN) {
755 dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
756 q6_state);
757 return -EPROBE_DEFER;
758 } else
759 dev_dbg(&pdev->dev, "adsp is ready\n");
760
761 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
762 "slimbus_physical");
763 if (!slim_mem) {
764 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
765 return -ENODEV;
766 }
767 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
768 "slimbus_bam_physical");
769 if (!bam_mem) {
770 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
771 return -ENODEV;
772 }
773 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
774 "slimbus_irq");
775 if (!irq) {
776 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
777 return -ENODEV;
778 }
779 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
780 "slimbus_bam_irq");
781 if (!bam_irq) {
782 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
783 return -ENODEV;
784 }
785
786 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
787 if (IS_ERR(dev)) {
788 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
789 return PTR_ERR(dev);
790 }
791 dev->dev = &pdev->dev;
792 platform_set_drvdata(pdev, dev);
793 slim_set_ctrldata(&dev->ctrl, dev);
794 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
795 if (!dev->base) {
796 dev_err(&pdev->dev, "IOremap failed\n");
797 ret = -ENOMEM;
798 goto err_ioremap_failed;
799 }
800 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
801 if (!dev->bam.base) {
802 dev_err(&pdev->dev, "BAM IOremap failed\n");
803 ret = -ENOMEM;
804 goto err_ioremap_bam_failed;
805 }
806 if (pdev->dev.of_node) {
807
808 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
809 &dev->ctrl.nr);
810 if (ret) {
811 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
812 goto err_ctrl_failed;
813 }
814 } else {
815 dev->ctrl.nr = pdev->id;
816 }
817 dev->ctrl.nchans = MSM_SLIM_NCHANS;
818 dev->ctrl.nports = MSM_SLIM_NPORTS;
819 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
820 dev->framer.superfreq =
821 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
822 dev->ctrl.a_framer = &dev->framer;
823 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
824 dev->ctrl.set_laddr = ngd_set_laddr;
825 dev->ctrl.get_laddr = ngd_get_laddr;
826 dev->ctrl.allocbw = ngd_allocbw;
827 dev->ctrl.xfer_msg = ngd_xfer_msg;
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700828 dev->ctrl.wakeup = ngd_clk_pause_wakeup;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600829 dev->ctrl.config_port = msm_config_port;
830 dev->ctrl.port_xfer = msm_slim_port_xfer;
831 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
832 /* Reserve some messaging BW for satellite-apps driver communication */
833 dev->ctrl.sched.pending_msgsl = 30;
834 dev->bam_mem = bam_mem;
835
836 init_completion(&dev->reconf);
837 mutex_init(&dev->tx_lock);
838 spin_lock_init(&dev->rx_lock);
839 dev->ee = 1;
840 dev->irq = irq->start;
841 dev->bam.irq = bam_irq->start;
842
843 dev->ver = readl_relaxed(dev->base);
844 /* Version info in 16 MSbits */
845 dev->ver >>= 16;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600846 init_completion(&dev->rx_msgq_notify);
847
848 /* Register with framework */
849 ret = slim_add_numbered_controller(&dev->ctrl);
850 if (ret) {
851 dev_err(dev->dev, "error adding controller\n");
852 goto err_ctrl_failed;
853 }
854
855 dev->ctrl.dev.parent = &pdev->dev;
856 dev->ctrl.dev.of_node = pdev->dev.of_node;
857 dev->state = MSM_CTRL_ASLEEP;
858
859 ret = request_irq(dev->irq, ngd_slim_interrupt,
860 IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
861
862 if (ret) {
863 dev_err(&pdev->dev, "request IRQ failed\n");
864 goto err_request_irq_failed;
865 }
866
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700867 init_completion(&dev->qmi.qmi_comp);
868 dev->qmi.nb.notifier_call = ngd_qmi_available;
869 ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
870 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
871 if (ret) {
872 pr_err("Slimbus QMI service registration failed:%d", ret);
873 goto qmi_register_failed;
874 }
875
Sagar Dharia71fcea52012-09-12 23:21:57 -0600876 /* Fire up the Rx message queue thread */
877 dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
878 NGD_SLIM_NAME "_ngd_msgq_thread");
879 if (IS_ERR(dev->rx_msgq_thread)) {
880 ret = PTR_ERR(dev->rx_msgq_thread);
881 dev_err(dev->dev, "Failed to start Rx message queue thread\n");
882 goto err_thread_create_failed;
883 }
884
Sagar Dharia71fcea52012-09-12 23:21:57 -0600885 if (pdev->dev.of_node)
886 of_register_slim_devices(&dev->ctrl);
887
888 /* Add devices registered with board-info now that controller is up */
889 slim_ctrl_add_boarddevs(&dev->ctrl);
890
Sagar Dharia71fcea52012-09-12 23:21:57 -0600891 dev_dbg(dev->dev, "NGD SB controller is up!\n");
892 return 0;
893
894err_thread_create_failed:
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700895 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
896 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
897qmi_register_failed:
Sagar Dharia71fcea52012-09-12 23:21:57 -0600898 free_irq(dev->irq, dev);
899err_request_irq_failed:
900 slim_del_controller(&dev->ctrl);
901err_ctrl_failed:
902 iounmap(dev->bam.base);
903err_ioremap_bam_failed:
904 iounmap(dev->base);
905err_ioremap_failed:
906 kfree(dev);
907 return ret;
908}
909
910static int __devexit ngd_slim_remove(struct platform_device *pdev)
911{
912 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700913 ngd_slim_enable(dev, false);
914 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
915 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600916 pm_runtime_disable(&pdev->dev);
917 pm_runtime_set_suspended(&pdev->dev);
918 free_irq(dev->irq, dev);
919 slim_del_controller(&dev->ctrl);
920 kthread_stop(dev->rx_msgq_thread);
921 iounmap(dev->bam.base);
922 iounmap(dev->base);
923 kfree(dev);
924 return 0;
925}
926
927#ifdef CONFIG_PM_RUNTIME
928static int ngd_slim_runtime_idle(struct device *device)
929{
930 dev_dbg(device, "pm_runtime: idle...\n");
931 pm_request_autosuspend(device);
932 return -EAGAIN;
933}
934#endif
935
936/*
937 * If PM_RUNTIME is not defined, these 2 functions become helper
938 * functions to be called from system suspend/resume. So they are not
939 * inside ifdef CONFIG_PM_RUNTIME
940 */
941#ifdef CONFIG_PM_SLEEP
942static int ngd_slim_runtime_suspend(struct device *device)
943{
944 struct platform_device *pdev = to_platform_device(device);
945 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
946 int ret;
947 dev_dbg(device, "pm_runtime: suspending...\n");
948 dev->state = MSM_CTRL_SLEEPING;
949 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
950 if (ret) {
951 dev_err(device, "clk pause not entered:%d", ret);
952 dev->state = MSM_CTRL_AWAKE;
953 } else {
954 dev->state = MSM_CTRL_ASLEEP;
955 }
956 return ret;
957}
958
959static int ngd_slim_runtime_resume(struct device *device)
960{
961 struct platform_device *pdev = to_platform_device(device);
962 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
963 int ret = 0;
964 dev_dbg(device, "pm_runtime: resuming...\n");
965 if (dev->state == MSM_CTRL_ASLEEP)
966 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
967 if (ret) {
968 dev_err(device, "clk pause not exited:%d", ret);
969 dev->state = MSM_CTRL_ASLEEP;
970 } else {
971 dev->state = MSM_CTRL_AWAKE;
972 }
973 return ret;
974}
975
976static int ngd_slim_suspend(struct device *dev)
977{
978 int ret = -EBUSY;
979 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
980 dev_dbg(dev, "system suspend");
981 ret = ngd_slim_runtime_suspend(dev);
982 }
983 if (ret == -EBUSY) {
984 /*
985 * There is a possibility that some audio stream is active
986 * during suspend. We dont want to return suspend failure in
987 * that case so that display and relevant components can still
988 * go to suspend.
989 * If there is some other error, then it should be passed-on
990 * to system level suspend
991 */
992 ret = 0;
993 }
994 return ret;
995}
996
997static int ngd_slim_resume(struct device *dev)
998{
999 /* If runtime_pm is enabled, this resume shouldn't do anything */
1000 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
1001 int ret;
1002 dev_dbg(dev, "system resume");
1003 ret = ngd_slim_runtime_resume(dev);
1004 if (!ret) {
1005 pm_runtime_mark_last_busy(dev);
1006 pm_request_autosuspend(dev);
1007 }
1008 return ret;
1009
1010 }
1011 return 0;
1012}
1013#endif /* CONFIG_PM_SLEEP */
1014
1015static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
1016 SET_SYSTEM_SLEEP_PM_OPS(
1017 ngd_slim_suspend,
1018 ngd_slim_resume
1019 )
1020 SET_RUNTIME_PM_OPS(
1021 ngd_slim_runtime_suspend,
1022 ngd_slim_runtime_resume,
1023 ngd_slim_runtime_idle
1024 )
1025};
1026
1027static struct of_device_id ngd_slim_dt_match[] = {
1028 {
1029 .compatible = "qcom,slim-ngd",
1030 },
1031 {}
1032};
1033
1034static struct platform_driver ngd_slim_driver = {
1035 .probe = ngd_slim_probe,
1036 .remove = ngd_slim_remove,
1037 .driver = {
1038 .name = NGD_SLIM_NAME,
1039 .owner = THIS_MODULE,
1040 .pm = &ngd_slim_dev_pm_ops,
1041 .of_match_table = ngd_slim_dt_match,
1042 },
1043};
1044
1045static int ngd_slim_init(void)
1046{
1047 return platform_driver_register(&ngd_slim_driver);
1048}
1049late_initcall(ngd_slim_init);
1050
1051static void ngd_slim_exit(void)
1052{
1053 platform_driver_unregister(&ngd_slim_driver);
1054}
1055module_exit(ngd_slim_exit);
1056
1057MODULE_LICENSE("GPL v2");
1058MODULE_DESCRIPTION("MSM Slimbus controller");
1059MODULE_ALIAS("platform:msm-slim-ngd");