blob: 0035349a33f5633269e2874fa337617c41fb59fd [file] [log] [blame]
Sagar Dharia32379162013-12-12 00:46:37 -07001/* Copyright (c) 2011-2014, 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 */
Sagar Dharia71fcea52012-09-12 23:21:57 -060012#include <linux/irq.h>
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/io.h>
17#include <linux/interrupt.h>
18#include <linux/platform_device.h>
19#include <linux/dma-mapping.h>
20#include <linux/slimbus/slimbus.h>
21#include <linux/delay.h>
22#include <linux/kthread.h>
23#include <linux/clk.h>
24#include <linux/pm_runtime.h>
25#include <linux/of.h>
26#include <linux/of_slimbus.h>
27#include <linux/timer.h>
28#include <mach/sps.h>
29#include "slim-msm.h"
Sagar Dharia71fcea52012-09-12 23:21:57 -060030
31#define NGD_SLIM_NAME "ngd_msm_ctrl"
32#define SLIM_LA_MGR 0xFF
33#define SLIM_ROOT_FREQ 24576000
Sagar Dharia33beca02012-10-22 16:21:46 -060034#define LADDR_RETRY 5
Sagar Dharia71fcea52012-09-12 23:21:57 -060035
36#define NGD_BASE_V1(r) (((r) % 2) ? 0x800 : 0xA00)
37#define NGD_BASE_V2(r) (((r) % 2) ? 0x1000 : 0x2000)
38#define NGD_BASE(r, v) ((v) ? NGD_BASE_V2(r) : NGD_BASE_V1(r))
39/* NGD (Non-ported Generic Device) registers */
40enum ngd_reg {
41 NGD_CFG = 0x0,
42 NGD_STATUS = 0x4,
43 NGD_RX_MSGQ_CFG = 0x8,
44 NGD_INT_EN = 0x10,
45 NGD_INT_STAT = 0x14,
46 NGD_INT_CLR = 0x18,
47 NGD_TX_MSG = 0x30,
48 NGD_RX_MSG = 0x70,
49 NGD_IE_STAT = 0xF0,
50 NGD_VE_STAT = 0x100,
51};
52
53enum ngd_msg_cfg {
54 NGD_CFG_ENABLE = 1,
55 NGD_CFG_RX_MSGQ_EN = 1 << 1,
56 NGD_CFG_TX_MSGQ_EN = 1 << 2,
57};
58
59enum ngd_intr {
60 NGD_INT_RECFG_DONE = 1 << 24,
61 NGD_INT_TX_NACKED_2 = 1 << 25,
62 NGD_INT_MSG_BUF_CONTE = 1 << 26,
63 NGD_INT_MSG_TX_INVAL = 1 << 27,
64 NGD_INT_IE_VE_CHG = 1 << 28,
65 NGD_INT_DEV_ERR = 1 << 29,
66 NGD_INT_RX_MSG_RCVD = 1 << 30,
67 NGD_INT_TX_MSG_SENT = 1 << 31,
68};
69
70enum ngd_offsets {
71 NGD_NACKED_MC = 0x7F00000,
72 NGD_ACKED_MC = 0xFE000,
73 NGD_ERROR = 0x1800,
74 NGD_MSGQ_SUPPORT = 0x400,
75 NGD_RX_MSGQ_TIME_OUT = 0x16,
76 NGD_ENUMERATED = 0x1,
77 NGD_TX_BUSY = 0x0,
78};
79
Sagar Dharia33beca02012-10-22 16:21:46 -060080enum ngd_status {
81 NGD_LADDR = 1 << 1,
82};
83
84static int ngd_slim_runtime_resume(struct device *device);
Sagar Dhariab94aa312014-01-14 17:36:32 -070085static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart);
Sagar Dharia33beca02012-10-22 16:21:46 -060086
Sagar Dharia71fcea52012-09-12 23:21:57 -060087static irqreturn_t ngd_slim_interrupt(int irq, void *d)
88{
89 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
90 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
91 u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
Sagar Dharia2b8a4b52013-05-15 20:01:45 -060092 u32 pstat;
Sagar Dharia71fcea52012-09-12 23:21:57 -060093
Sagar Dhariafc690502014-02-03 12:17:04 -070094 if ((stat & NGD_INT_MSG_BUF_CONTE) ||
95 (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
96 (stat & NGD_INT_TX_NACKED_2)) {
97 writel_relaxed(stat, ngd + NGD_INT_CLR);
98 dev->err = -EIO;
99
Kiran Gundab27683f2014-01-07 15:58:31 +0530100 SLIM_WARN(dev, "NGD interrupt error:0x%x, err:%d\n", stat,
Sagar Dhariafc690502014-02-03 12:17:04 -0700101 dev->err);
102 /* Guarantee that error interrupts are cleared */
103 mb();
104 if (dev->wr_comp)
105 complete(dev->wr_comp);
106
107 } else if (stat & NGD_INT_TX_MSG_SENT) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600108 writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
109 /* Make sure interrupt is cleared */
110 mb();
111 if (dev->wr_comp)
112 complete(dev->wr_comp);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600113 }
114 if (stat & NGD_INT_RX_MSG_RCVD) {
115 u32 rx_buf[10];
116 u8 len, i;
117 rx_buf[0] = readl_relaxed(ngd + NGD_RX_MSG);
118 len = rx_buf[0] & 0x1F;
119 for (i = 1; i < ((len + 3) >> 2); i++) {
120 rx_buf[i] = readl_relaxed(ngd + NGD_RX_MSG +
121 (4 * i));
Kiran Gundab27683f2014-01-07 15:58:31 +0530122 SLIM_DBG(dev, "REG-RX data: %x\n", rx_buf[i]);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600123 }
124 msm_slim_rx_enqueue(dev, rx_buf, len);
125 writel_relaxed(NGD_INT_RX_MSG_RCVD,
126 ngd + NGD_INT_CLR);
127 /*
128 * Guarantee that CLR bit write goes through before
129 * queuing work
130 */
131 mb();
Sagar Dharia24419e32013-01-14 17:56:32 -0700132 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Kiran Gundab27683f2014-01-07 15:58:31 +0530133 SLIM_WARN(dev, "direct msg rcvd with RX MSGQs\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600134 else
135 complete(&dev->rx_msgq_notify);
136 }
137 if (stat & NGD_INT_RECFG_DONE) {
138 writel_relaxed(NGD_INT_RECFG_DONE, ngd + NGD_INT_CLR);
139 /* Guarantee RECONFIG DONE interrupt is cleared */
140 mb();
141 /* In satellite mode, just log the reconfig done IRQ */
Kiran Gundab27683f2014-01-07 15:58:31 +0530142 SLIM_DBG(dev, "reconfig done IRQ for NGD\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600143 }
144 if (stat & NGD_INT_IE_VE_CHG) {
145 writel_relaxed(NGD_INT_IE_VE_CHG, ngd + NGD_INT_CLR);
146 /* Guarantee IE VE change interrupt is cleared */
147 mb();
Kiran Gundab27683f2014-01-07 15:58:31 +0530148 SLIM_DBG(dev, "NGD IE VE change\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600149 }
Sagar Dharia2b8a4b52013-05-15 20:01:45 -0600150
151 pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
152 if (pstat != 0)
153 return msm_slim_port_irq_handler(dev, pstat);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600154 return IRQ_HANDLED;
155}
156
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700157static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
158 void *_cmd)
159{
160 struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
Sagar Dharia33beca02012-10-22 16:21:46 -0600161 struct msm_slim_ctrl *dev =
162 container_of(qmi, struct msm_slim_ctrl, qmi);
Kiran Gundab27683f2014-01-07 15:58:31 +0530163 SLIM_INFO(dev, "Slimbus QMI NGD CB received event:%ld\n", code);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700164 switch (code) {
165 case QMI_SERVER_ARRIVE:
Sagar Dharia33beca02012-10-22 16:21:46 -0600166 schedule_work(&qmi->ssr_up);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700167 break;
168 case QMI_SERVER_EXIT:
Sagar Dharia33beca02012-10-22 16:21:46 -0600169 dev->state = MSM_CTRL_DOWN;
170 /* make sure autosuspend is not called until ADSP comes up*/
171 pm_runtime_get_noresume(dev->dev);
172 /* Reset ctrl_up completion */
173 init_completion(&dev->ctrl_up);
174 schedule_work(&qmi->ssr_down);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700175 break;
176 default:
177 break;
178 }
179 return 0;
180}
181
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600182static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
183 void *_cmd)
184{
Sagar Dhariab94aa312014-01-14 17:36:32 -0700185 void __iomem *ngd;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600186 struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
187 struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
188 mdm);
Sagar Dhariab94aa312014-01-14 17:36:32 -0700189 struct slim_controller *ctrl = &dev->ctrl;
190 u32 laddr;
191 struct slim_device *sbdev;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600192
193 switch (code) {
194 case SUBSYS_BEFORE_SHUTDOWN:
Kiran Gundab27683f2014-01-07 15:58:31 +0530195 SLIM_INFO(dev, "SLIM %lu external_modem SSR notify cb\n", code);
Sagar Dhariab94aa312014-01-14 17:36:32 -0700196 /* vote for runtime-pm so that ADSP doesn't go down */
Sagar Dharia327bf642014-04-08 16:30:25 -0600197 msm_slim_get_ctrl(dev);
Sagar Dhariab94aa312014-01-14 17:36:32 -0700198 /*
199 * checking framer here will wake-up ADSP and may avoid framer
200 * handover later
201 */
202 msm_slim_qmi_check_framer_request(dev);
203 dev->mdm.state = MSM_CTRL_DOWN;
Sagar Dharia327bf642014-04-08 16:30:25 -0600204 msm_slim_put_ctrl(dev);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600205 break;
206 case SUBSYS_AFTER_POWERUP:
Sagar Dhariab94aa312014-01-14 17:36:32 -0700207 if (dev->mdm.state != MSM_CTRL_DOWN)
208 return NOTIFY_DONE;
Kiran Gundab27683f2014-01-07 15:58:31 +0530209 SLIM_INFO(dev,
210 "SLIM %lu external_modem SSR notify cb\n", code);
Sagar Dharia327bf642014-04-08 16:30:25 -0600211 /* vote for runtime-pm so that ADSP doesn't go down */
212 msm_slim_get_ctrl(dev);
Sagar Dhariab94aa312014-01-14 17:36:32 -0700213 msm_slim_qmi_check_framer_request(dev);
214 /* If NGD enumeration is lost, we will need to power us up */
215 ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
216 laddr = readl_relaxed(ngd + NGD_STATUS);
217 if (!(laddr & NGD_LADDR)) {
Sagar Dharia327bf642014-04-08 16:30:25 -0600218 /* runtime-pm state should be consistent with HW */
219 pm_runtime_disable(dev->dev);
220 pm_runtime_set_suspended(dev->dev);
221 dev->state = MSM_CTRL_DOWN;
Kiran Gundab27683f2014-01-07 15:58:31 +0530222 SLIM_INFO(dev,
223 "SLIM MDM SSR (active framer on MDM) dev-down\n");
Sagar Dhariab94aa312014-01-14 17:36:32 -0700224 list_for_each_entry(sbdev, &ctrl->devs, dev_list)
225 slim_report_absent(sbdev);
Sagar Dharia327bf642014-04-08 16:30:25 -0600226 ngd_slim_power_up(dev, true);
227 pm_runtime_set_active(dev->dev);
228 pm_runtime_enable(dev->dev);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600229 }
Sagar Dhariab94aa312014-01-14 17:36:32 -0700230 dev->mdm.state = MSM_CTRL_AWAKE;
Sagar Dharia327bf642014-04-08 16:30:25 -0600231 msm_slim_put_ctrl(dev);
Sagar Dhariab94aa312014-01-14 17:36:32 -0700232 break;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600233 default:
234 break;
235 }
236 return NOTIFY_DONE;
237}
238
Sagar Dharia71fcea52012-09-12 23:21:57 -0600239static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
240 u8 *tid, struct completion *done)
241{
242 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariad2959352012-12-01 15:43:01 -0700243 mutex_lock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600244 if (ctrl->last_tid <= 255) {
245 ctrl->txnt = krealloc(ctrl->txnt,
246 (ctrl->last_tid + 1) *
247 sizeof(struct slim_msg_txn *),
248 GFP_KERNEL);
Sagar Dhariad2959352012-12-01 15:43:01 -0700249 if (!ctrl->txnt) {
250 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600251 return -ENOMEM;
Sagar Dhariad2959352012-12-01 15:43:01 -0700252 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600253 dev->msg_cnt = ctrl->last_tid;
254 ctrl->last_tid++;
255 } else {
256 int i;
257 for (i = 0; i < 256; i++) {
258 dev->msg_cnt = ((dev->msg_cnt + 1) & 0xFF);
259 if (ctrl->txnt[dev->msg_cnt] == NULL)
260 break;
261 }
262 if (i >= 256) {
263 dev_err(&ctrl->dev, "out of TID");
Sagar Dhariad2959352012-12-01 15:43:01 -0700264 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600265 return -ENOMEM;
266 }
267 }
268 ctrl->txnt[dev->msg_cnt] = txn;
269 txn->tid = dev->msg_cnt;
270 txn->comp = done;
271 *tid = dev->msg_cnt;
Sagar Dhariad2959352012-12-01 15:43:01 -0700272 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600273 return 0;
274}
275static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
276{
277 DECLARE_COMPLETION_ONSTACK(done);
278 DECLARE_COMPLETION_ONSTACK(tx_sent);
279
280 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
281 u32 *pbuf;
282 u8 *puc;
283 int ret = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600284 u8 la = txn->la;
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600285 u8 txn_mt;
286 u16 txn_mc = txn->mc;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600287 u8 wbuf[SLIM_MSGQ_BUF_LEN];
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700288 bool report_sat = false;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600289
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700290 if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
291 txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
292 report_sat = true;
Sagar Dhariaa1398282013-01-22 13:26:20 -0700293 if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700294 report_sat == false) {
Sagar Dhariaa1398282013-01-22 13:26:20 -0700295 /*
296 * Counter-part of system-suspend when runtime-pm is not enabled
297 * This way, resume can be left empty and device will be put in
298 * active mode only if client requests anything on the bus
299 * If the state was DOWN, SSR UP notification will take
300 * care of putting the device in active state.
301 */
302 ngd_slim_runtime_resume(dev->dev);
303 }
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600304 if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
305 SLIM_MSG_MC_RECONFIGURE_NOW)) &&
Sagar Dhariad1468b72013-07-16 12:56:22 -0600306 dev->state <= MSM_CTRL_IDLE) {
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600307 msm_slim_disconnect_endp(dev, &dev->rx_msgq,
308 &dev->use_rx_msgqs);
309 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
310 &dev->use_tx_msgqs);
311 return msm_slim_qmi_power_request(dev, false);
Sagar Dharia24419e32013-01-14 17:56:32 -0700312 }
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700313 else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
314 return 0;
315
Sagar Dharia71fcea52012-09-12 23:21:57 -0600316 if (txn->mt == SLIM_MSG_MT_CORE &&
317 (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
318 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
319 return 0;
320 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600321 /* If txn is tried when controller is down, wait for ADSP to boot */
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700322 if (!report_sat) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600323 if (dev->state == MSM_CTRL_DOWN) {
324 u8 mc = (u8)txn->mc;
325 int timeout;
Kiran Gundab27683f2014-01-07 15:58:31 +0530326 SLIM_INFO(dev, "ADSP slimbus not up yet\n");
Sagar Dharia33beca02012-10-22 16:21:46 -0600327 /*
328 * Messages related to data channel management can't
329 * wait since they are holding reconfiguration lock.
330 * clk_pause in resume (which can change state back to
Sagar Dharia32379162013-12-12 00:46:37 -0700331 * MSM_CTRL_AWAKE), will need that lock.
332 * Port disconnection, channel removal calls should pass
333 * through since there is no activity on the bus and
334 * those calls are triggered by clients due to
335 * device_down callback in that situation.
336 * Returning 0 on the disconnections and
337 * removals will ensure consistent state of channels,
338 * ports with the HW
Sagar Dharia55bced82014-01-20 16:00:44 -0700339 * Remote requests to remove channel/port will be
340 * returned from the path where they wait on
341 * acknowledgement from ADSP
Sagar Dharia33beca02012-10-22 16:21:46 -0600342 */
Sagar Dharia32379162013-12-12 00:46:37 -0700343 if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
344 ((mc == SLIM_USR_MC_CHAN_CTRL ||
345 mc == SLIM_USR_MC_DISCONNECT_PORT ||
346 mc == SLIM_USR_MC_RECONFIG_NOW)))
Sagar Dharia55bced82014-01-20 16:00:44 -0700347 return -EREMOTEIO;
Sagar Dharia32379162013-12-12 00:46:37 -0700348 if ((txn->mt == SLIM_MSG_MT_CORE) &&
349 ((mc == SLIM_MSG_MC_DISCONNECT_PORT ||
350 mc == SLIM_MSG_MC_NEXT_REMOVE_CHANNEL ||
351 mc == SLIM_USR_MC_RECONFIG_NOW)))
352 return 0;
Sagar Dharia33beca02012-10-22 16:21:46 -0600353 if ((txn->mt == SLIM_MSG_MT_CORE) &&
354 ((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
355 mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
356 (mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
357 mc <= SLIM_MSG_MC_RECONFIGURE_NOW)))
358 return -EREMOTEIO;
359 if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
360 ((mc >= SLIM_USR_MC_DEFINE_CHAN &&
Sagar Dharia32379162013-12-12 00:46:37 -0700361 mc < SLIM_USR_MC_DISCONNECT_PORT)))
Sagar Dharia33beca02012-10-22 16:21:46 -0600362 return -EREMOTEIO;
363 timeout = wait_for_completion_timeout(&dev->ctrl_up,
364 HZ);
Sagar Dharia4f240722014-01-15 13:50:58 -0700365 if (!timeout && dev->state == MSM_CTRL_DOWN)
Sagar Dharia33beca02012-10-22 16:21:46 -0600366 return -ETIMEDOUT;
367 }
Sagar Dharia129c7d82013-08-08 19:35:50 -0600368 ret = msm_slim_get_ctrl(dev);
369 /*
370 * Runtime-pm's callbacks are not called until runtime-pm's
371 * error status is cleared
372 * Setting runtime status to suspended clears the error
373 * It also makes HW status cosistent with what SW has it here
374 */
375 if (ret == -ENETRESET && dev->state == MSM_CTRL_DOWN) {
376 pm_runtime_set_suspended(dev->dev);
377 msm_slim_put_ctrl(dev);
378 return -EREMOTEIO;
Sagar Dhariad1468b72013-07-16 12:56:22 -0600379 } else if (ret >= 0) {
380 dev->state = MSM_CTRL_AWAKE;
Sagar Dharia129c7d82013-08-08 19:35:50 -0600381 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600382 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600383 mutex_lock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600384
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700385 if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530386 SLIM_ERR(dev, "controller not ready\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600387 mutex_unlock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600388 msm_slim_put_ctrl(dev);
389 return -EREMOTEIO;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600390 }
391 if (txn->mt == SLIM_MSG_MT_CORE &&
392 (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
393 txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
394 txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
395 int i = 0;
Kiran Gundab27683f2014-01-07 15:58:31 +0530396 if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
397 SLIM_INFO(dev,
398 "Connect port: laddr 0x%x port_num %d chan_num %d\n",
399 txn->la, txn->wbuf[0], txn->wbuf[1]);
400 else
401 SLIM_INFO(dev,
402 "Disconnect port: laddr 0x%x port_num %d\n",
403 txn->la, txn->wbuf[0]);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600404 txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
405 if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
406 txn->mc = SLIM_USR_MC_CONNECT_SRC;
407 else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
408 txn->mc = SLIM_USR_MC_CONNECT_SINK;
409 else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
410 txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600411 if (txn->la == SLIM_LA_MGR) {
412 if (dev->pgdla == SLIM_LA_MGR) {
413 u8 ea[] = {0, QC_DEVID_PGD, 0, 0, QC_MFGID_MSB,
414 QC_MFGID_LSB};
415 ea[2] = (u8)(dev->pdata.eapc & 0xFF);
416 ea[3] = (u8)((dev->pdata.eapc & 0xFF00) >> 8);
417 mutex_unlock(&dev->tx_lock);
418 ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
419 &dev->pgdla);
Kiran Gundab27683f2014-01-07 15:58:31 +0530420 SLIM_DBG(dev, "SLIM PGD LA:0x%x, ret:%d\n",
421 dev->pgdla, ret);
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600422 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530423 SLIM_ERR(dev,
424 "Incorrect SLIM-PGD EAPC:0x%x\n",
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600425 dev->pdata.eapc);
426 return ret;
427 }
428 mutex_lock(&dev->tx_lock);
429 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600430 txn->la = dev->pgdla;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600431 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600432 wbuf[i++] = txn->la;
433 la = SLIM_LA_MGR;
434 wbuf[i++] = txn->wbuf[0];
435 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
436 wbuf[i++] = txn->wbuf[1];
437 ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
438 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530439 SLIM_ERR(dev, "TID for connect/disconnect fail:%d\n",
440 ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600441 goto ngd_xfer_err;
442 }
443 txn->len = i;
444 txn->wbuf = wbuf;
445 txn->rl = txn->len + 4;
446 }
447 txn->rl--;
448 pbuf = msm_get_msg_buf(dev, txn->rl);
449 if (!pbuf) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530450 SLIM_ERR(dev, "Message buffer unavailable\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600451 ret = -ENOMEM;
452 goto ngd_xfer_err;
453 }
454 dev->err = 0;
455
456 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
457 ret = -EPROTONOSUPPORT;
458 goto ngd_xfer_err;
459 }
460 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
461 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
462 la);
463 else
464 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
465 la);
466 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
467 puc = ((u8 *)pbuf) + 3;
468 else
469 puc = ((u8 *)pbuf) + 2;
470 if (txn->rbuf)
471 *(puc++) = txn->tid;
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700472 if (((txn->mt == SLIM_MSG_MT_CORE) &&
Sagar Dharia71fcea52012-09-12 23:21:57 -0600473 ((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
474 txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
475 (txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700476 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) ||
477 (txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
478 txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600479 *(puc++) = (txn->ec & 0xFF);
480 *(puc++) = (txn->ec >> 8)&0xFF;
481 }
482 if (txn->wbuf)
483 memcpy(puc, txn->wbuf, txn->len);
484 if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
485 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
486 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
487 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
488 wbuf[0] == dev->pgdla) {
Sagar Dharia2d74c142013-05-17 02:24:06 -0600489 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600490 dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
491 else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600492 /*
493 * Remove channel disconnects master-side ports from
494 * channel. No need to send that again on the bus
Sagar Dharia2d74c142013-05-17 02:24:06 -0600495 * Only disable port
Sagar Dharia71fcea52012-09-12 23:21:57 -0600496 */
Sagar Dharia2d74c142013-05-17 02:24:06 -0600497 writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
498 (wbuf[1] + dev->port_b), dev->ver));
Sagar Dharia71fcea52012-09-12 23:21:57 -0600499 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700500 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600501 return 0;
502 }
503 if (dev->err) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530504 SLIM_ERR(dev, "pipe-port connect err:%d\n", dev->err);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600505 goto ngd_xfer_err;
506 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600507 /* Add port-base to port number if this is manager side port */
508 puc[1] += dev->port_b;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600509 }
510 dev->err = 0;
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600511 /*
512 * If it's a read txn, it may be freed if a response is received by
513 * received thread before reaching end of this function.
514 * mc, mt may have changed to convert standard slimbus code/type to
515 * satellite user-defined message. Reinitialize again
516 */
517 txn_mc = txn->mc;
518 txn_mt = txn->mt;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600519 dev->wr_comp = &tx_sent;
520 ret = msm_send_msg_buf(dev, pbuf, txn->rl,
521 NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
522 if (!ret) {
523 int timeout = wait_for_completion_timeout(&tx_sent, HZ);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600524 if (!timeout) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600525 ret = -ETIMEDOUT;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600526 /*
527 * disconnect/recoonect pipe so that subsequent
528 * transactions don't timeout due to unavailable
529 * descriptors
530 */
531 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
532 &dev->use_tx_msgqs);
533 msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
534 } else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600535 ret = dev->err;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600536 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600537 }
538 dev->wr_comp = NULL;
539 if (ret) {
540 u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
541 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
542 dev->ver);
Kiran Gundab27683f2014-01-07 15:58:31 +0530543 SLIM_WARN(dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d\n",
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600544 txn_mc, txn_mt, ret, dev->ver);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600545 conf = readl_relaxed(ngd);
546 stat = readl_relaxed(ngd + NGD_STATUS);
547 rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
548 int_stat = readl_relaxed(ngd + NGD_INT_STAT);
549 int_en = readl_relaxed(ngd + NGD_INT_EN);
550 int_clr = readl_relaxed(ngd + NGD_INT_CLR);
551
Kiran Gundab27683f2014-01-07 15:58:31 +0530552 SLIM_WARN(dev, "conf:0x%x,stat:0x%x,rxmsgq:0x%x\n",
553 conf, stat, rx_msgq);
554 SLIM_WARN(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
555 int_stat, int_en, int_clr);
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600556 } else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
557 (txn_mc == SLIM_USR_MC_CONNECT_SRC ||
558 txn_mc == SLIM_USR_MC_CONNECT_SINK ||
559 txn_mc == SLIM_USR_MC_DISCONNECT_PORT)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600560 int timeout;
561 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700562 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600563 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600564 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600565 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600566 else
567 ret = txn->ec;
568 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530569 SLIM_INFO(dev,
570 "connect/disconnect:0x%x,tid:%d err:%d\n",
571 txn->mc, txn->tid, ret);
Sagar Dhariad2959352012-12-01 15:43:01 -0700572 mutex_lock(&ctrl->m_ctrl);
573 ctrl->txnt[txn->tid] = NULL;
574 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600575 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600576 return ret ? ret : dev->err;
577 }
578ngd_xfer_err:
579 mutex_unlock(&dev->tx_lock);
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700580 if (!report_sat)
Sagar Dharia33beca02012-10-22 16:21:46 -0600581 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600582 return ret ? ret : dev->err;
583}
584
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700585static int ngd_user_msg(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc,
586 struct slim_ele_access *msg, u8 *buf, u8 len)
587{
588 struct slim_msg_txn txn;
589
590 if (mt != SLIM_MSG_MT_DEST_REFERRED_USER ||
591 mc != SLIM_USR_MC_REPEAT_CHANGE_VALUE) {
592 return -EPROTONOSUPPORT;
593 }
594 if (len > SLIM_MAX_VE_SLC_BYTES ||
595 msg->start_offset > MSM_SLIM_VE_MAX_MAP_ADDR)
596 return -EINVAL;
597 if (len <= 4) {
598 txn.ec = len - 1;
599 } else if (len <= 8) {
600 if (len & 0x1)
601 return -EINVAL;
602 txn.ec = ((len >> 1) + 1);
603 } else {
604 if (len & 0x3)
605 return -EINVAL;
606 txn.ec = ((len >> 2) + 3);
607 }
608 txn.ec |= (0x8 | ((msg->start_offset & 0xF) << 4));
609 txn.ec |= ((msg->start_offset & 0xFF0) << 4);
610
611 txn.la = la;
612 txn.mt = mt;
613 txn.mc = mc;
614 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
615 txn.len = len;
616 txn.rl = len + 6;
617 txn.wbuf = buf;
618 txn.rbuf = NULL;
619 txn.comp = msg->comp;
620 return ngd_xfer_msg(ctrl, &txn);
621}
622
Sagar Dharia71fcea52012-09-12 23:21:57 -0600623static int ngd_xferandwait_ack(struct slim_controller *ctrl,
624 struct slim_msg_txn *txn)
625{
Kiran Gundab27683f2014-01-07 15:58:31 +0530626 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600627 int ret = ngd_xfer_msg(ctrl, txn);
628 if (!ret) {
629 int timeout;
630 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600631 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600632 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600633 else
Sagar Dharia71fcea52012-09-12 23:21:57 -0600634 ret = txn->ec;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600635 }
Sagar Dharia55bced82014-01-20 16:00:44 -0700636
Sagar Dharia33beca02012-10-22 16:21:46 -0600637 if (ret) {
Sagar Dharia21f88552014-02-07 00:10:37 -0700638 if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
Kiran Gundab27683f2014-01-07 15:58:31 +0530639 SLIM_ERR(dev, "master msg:0x%x,tid:%d ret:%d\n",
640 txn->mc, txn->tid, ret);
Sagar Dharia33beca02012-10-22 16:21:46 -0600641 mutex_lock(&ctrl->m_ctrl);
642 ctrl->txnt[txn->tid] = NULL;
643 mutex_unlock(&ctrl->m_ctrl);
644 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600645
646 return ret;
647}
648
649static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
650{
Kiran Gundab27683f2014-01-07 15:58:31 +0530651 int ret = 0, num_chan = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600652 struct slim_pending_ch *pch;
653 struct slim_msg_txn txn;
654 struct slim_controller *ctrl = sb->ctrl;
655 DECLARE_COMPLETION_ONSTACK(done);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600656 u8 wbuf[SLIM_MSGQ_BUF_LEN];
Kiran Gundab27683f2014-01-07 15:58:31 +0530657 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600658
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600659 *clkgear = ctrl->clkgear;
660 *subfrmc = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600661 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
662 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
663 txn.la = SLIM_LA_MGR;
664 txn.len = 0;
665 txn.ec = 0;
666 txn.wbuf = wbuf;
667 txn.rbuf = NULL;
668
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600669 if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530670 SLIM_DBG(dev, "slim reserve BW for messaging: req: %d\n",
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600671 ctrl->sched.pending_msgsl);
672 txn.mc = SLIM_USR_MC_REQ_BW;
673 wbuf[txn.len++] = ((sb->laddr & 0x1f) |
674 ((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
675 wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
676 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
677 if (ret)
678 return ret;
679 txn.rl = txn.len + 4;
680 ret = ngd_xferandwait_ack(ctrl, &txn);
681 if (ret)
682 return ret;
683
684 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
685 txn.len = 2;
686 wbuf[1] = sb->laddr;
687 txn.rl = txn.len + 4;
688 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
689 if (ret)
690 return ret;
691 ret = ngd_xferandwait_ack(ctrl, &txn);
692 if (ret)
693 return ret;
694
695 txn.len = 0;
696 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600697 list_for_each_entry(pch, &sb->mark_define, pending) {
698 struct slim_ich *slc;
699 slc = &ctrl->chans[pch->chan];
700 if (!slc) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530701 SLIM_WARN(dev, "no channel in define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600702 return -ENXIO;
703 }
704 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600705 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600706 wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600707 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600708 wbuf[txn.len] = slc->seglen;
709 if (slc->coeff == SLIM_COEFF_3)
710 wbuf[txn.len] |= 1 << 5;
711 wbuf[txn.len++] |= slc->prop.auxf << 6;
712 wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
713 wbuf[txn.len++] = slc->prrate;
714 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
715 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530716 SLIM_WARN(dev, "no tid for channel define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600717 return -ENXIO;
718 }
719 }
Kiran Gundab27683f2014-01-07 15:58:31 +0530720 num_chan++;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600721 wbuf[txn.len++] = slc->chan;
Kiran Gundab27683f2014-01-07 15:58:31 +0530722 SLIM_INFO(dev, "slim activate chan:%d, laddr: 0x%x\n",
723 slc->chan, sb->laddr);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600724 }
725 if (txn.len) {
726 txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
727 txn.rl = txn.len + 4;
728 ret = ngd_xferandwait_ack(ctrl, &txn);
729 if (ret)
730 return ret;
731
732 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
733 txn.len = 2;
734 wbuf[1] = sb->laddr;
735 txn.rl = txn.len + 4;
736 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
737 if (ret)
738 return ret;
739 ret = ngd_xferandwait_ack(ctrl, &txn);
740 if (ret)
741 return ret;
742 }
743 txn.len = 0;
744 list_for_each_entry(pch, &sb->mark_removal, pending) {
745 struct slim_ich *slc;
746 slc = &ctrl->chans[pch->chan];
747 if (!slc) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530748 SLIM_WARN(dev, "no channel in removal?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600749 return -ENXIO;
750 }
751 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600752 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600753 wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600754 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600755 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
756 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530757 SLIM_WARN(dev, "no tid for channel define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600758 return -ENXIO;
759 }
760 }
761 wbuf[txn.len++] = slc->chan;
Kiran Gundab27683f2014-01-07 15:58:31 +0530762 SLIM_INFO(dev, "slim remove chan:%d, laddr: 0x%x\n",
763 slc->chan, sb->laddr);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600764 }
765 if (txn.len) {
766 txn.mc = SLIM_USR_MC_CHAN_CTRL;
767 txn.rl = txn.len + 4;
768 ret = ngd_xferandwait_ack(ctrl, &txn);
Sagar Dharia21f88552014-02-07 00:10:37 -0700769 /* HW restarting, channel removal should succeed */
770 if (ret == -EREMOTEIO)
771 return 0;
772 else if (ret)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600773 return ret;
774
775 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
776 txn.len = 2;
777 wbuf[1] = sb->laddr;
778 txn.rl = txn.len + 4;
779 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
780 if (ret)
781 return ret;
782 ret = ngd_xferandwait_ack(ctrl, &txn);
783 if (ret)
784 return ret;
785 txn.len = 0;
786 }
Sagar Dharia24419e32013-01-14 17:56:32 -0700787 return 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600788}
789
790static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
791 u8 elen, u8 laddr)
792{
793 return 0;
794}
795
796static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
797 u8 elen, u8 *laddr)
798{
799 int ret;
800 u8 wbuf[10];
801 struct slim_msg_txn txn;
802 DECLARE_COMPLETION_ONSTACK(done);
803 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
804 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
805 txn.la = SLIM_LA_MGR;
806 txn.ec = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600807 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
808 if (ret) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600809 return ret;
810 }
811 memcpy(&wbuf[1], ea, elen);
812 txn.mc = SLIM_USR_MC_ADDR_QUERY;
813 txn.rl = 11;
814 txn.len = 7;
815 txn.wbuf = wbuf;
816 txn.rbuf = NULL;
817 ret = ngd_xferandwait_ack(ctrl, &txn);
818 if (!ret && txn.la == 0xFF)
819 ret = -ENXIO;
820 else if (!ret)
821 *laddr = txn.la;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600822 return ret;
823}
824
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600825static void ngd_slim_setup_msg_path(struct msm_slim_ctrl *dev)
Sagar Dharia24419e32013-01-14 17:56:32 -0700826{
Sagar Dharia24419e32013-01-14 17:56:32 -0700827 if (dev->state == MSM_CTRL_DOWN) {
828 msm_slim_sps_init(dev, dev->bam_mem,
829 NGD_BASE(dev->ctrl.nr,
830 dev->ver) + NGD_STATUS, true);
831 } else {
832 if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600833 goto setup_tx_msg_path;
834 msm_slim_connect_endp(dev, &dev->rx_msgq,
Sagar Dharia24419e32013-01-14 17:56:32 -0700835 &dev->rx_msgq_notify);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600836
837setup_tx_msg_path:
838 if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
839 return;
840 msm_slim_connect_endp(dev, &dev->tx_msgq,
841 NULL);
Sagar Dharia24419e32013-01-14 17:56:32 -0700842 }
843}
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600844
Sagar Dharia71fcea52012-09-12 23:21:57 -0600845static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
846{
847 u8 mc, mt, len;
848 int ret;
849 u32 msgq_en = 1;
850
851 len = buf[0] & 0x1F;
852 mt = (buf[0] >> 5) & 0x7;
853 mc = buf[1];
854 if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
855 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
856 struct slim_msg_txn txn;
Sagar Dharia0a693332013-04-15 17:59:03 -0600857 int retries = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600858 u8 wbuf[8];
859 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
860 txn.ec = 0;
861 txn.rbuf = NULL;
862 txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
863 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
864 txn.la = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600865 wbuf[0] = SAT_MAGIC_LSB;
866 wbuf[1] = SAT_MAGIC_MSB;
867 wbuf[2] = SAT_MSG_VER;
868 wbuf[3] = SAT_MSG_PROT;
869 txn.wbuf = wbuf;
870 txn.len = 4;
Kiran Gundab27683f2014-01-07 15:58:31 +0530871 SLIM_INFO(dev, "SLIM SAT: Rcvd master capability\n");
Sagar Dharia24419e32013-01-14 17:56:32 -0700872 if (dev->state >= MSM_CTRL_ASLEEP) {
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600873 ngd_slim_setup_msg_path(dev);
Sagar Dharia24419e32013-01-14 17:56:32 -0700874 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Sagar Dharia33beca02012-10-22 16:21:46 -0600875 msgq_en |= NGD_CFG_RX_MSGQ_EN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600876 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
877 msgq_en |= NGD_CFG_TX_MSGQ_EN;
Sagar Dharia33beca02012-10-22 16:21:46 -0600878 writel_relaxed(msgq_en, dev->base +
879 NGD_BASE(dev->ctrl.nr, dev->ver));
880 /* make sure NGD MSG-Q config goes through */
881 mb();
882 }
Sagar Dharia0a693332013-04-15 17:59:03 -0600883capability_retry:
884 txn.rl = 8;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600885 ret = ngd_xfer_msg(&dev->ctrl, &txn);
886 if (!ret) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600887 enum msm_ctrl_state prev_state = dev->state;
Kiran Gundab27683f2014-01-07 15:58:31 +0530888 SLIM_INFO(dev,
889 "SLIM SAT: capability exchange successful\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600890 dev->state = MSM_CTRL_AWAKE;
Sagar Dharia33beca02012-10-22 16:21:46 -0600891 if (prev_state >= MSM_CTRL_ASLEEP)
892 complete(&dev->reconf);
893 else
Kiran Gundab27683f2014-01-07 15:58:31 +0530894 SLIM_ERR(dev,
895 "SLIM: unexpected capability, state:%d\n",
896 prev_state);
Sagar Dharia33beca02012-10-22 16:21:46 -0600897 /* ADSP SSR, send device_up notifications */
898 if (prev_state == MSM_CTRL_DOWN)
Sagar Dhariae44cc822014-02-07 21:32:34 -0700899 complete(&dev->qmi.slave_notify);
Sagar Dharia0a693332013-04-15 17:59:03 -0600900 } else if (ret == -EIO) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530901 SLIM_WARN(dev, "capability message NACKed, retrying\n");
Sagar Dharia0a693332013-04-15 17:59:03 -0600902 if (retries < INIT_MX_RETRIES) {
903 msleep(DEF_RETRY_MS);
904 retries++;
905 goto capability_retry;
906 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600907 }
908 }
909 if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
910 mc == SLIM_MSG_MC_REPLY_VALUE) {
911 u8 tid = buf[3];
912 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
913 slim_msg_response(&dev->ctrl, &buf[4], tid,
914 len - 4);
915 pm_runtime_mark_last_busy(dev->dev);
916 }
917 if (mc == SLIM_USR_MC_ADDR_REPLY &&
918 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700919 struct slim_msg_txn *txn;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600920 u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
Sagar Dhariad2959352012-12-01 15:43:01 -0700921 mutex_lock(&dev->ctrl.m_ctrl);
922 txn = dev->ctrl.txnt[buf[3]];
923 if (!txn) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530924 SLIM_WARN(dev,
925 "LADDR response after timeout, tid:0x%x\n",
926 buf[3]);
Sagar Dhariad2959352012-12-01 15:43:01 -0700927 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600928 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700929 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600930 if (memcmp(&buf[4], failed_ea, 6))
931 txn->la = buf[10];
932 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700933 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600934 complete(txn->comp);
935 }
936 if (mc == SLIM_USR_MC_GENERIC_ACK &&
937 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700938 struct slim_msg_txn *txn;
939 mutex_lock(&dev->ctrl.m_ctrl);
940 txn = dev->ctrl.txnt[buf[3]];
941 if (!txn) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530942 SLIM_WARN(dev, "ACK received after timeout, tid:0x%x\n",
Sagar Dhariad2959352012-12-01 15:43:01 -0700943 buf[3]);
944 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600945 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700946 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600947 dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
948 (int)buf[3], buf[4]);
949 if (!(buf[4] & MSM_SAT_SUCCSS)) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530950 SLIM_WARN(dev, "TID:%d, NACK code:0x%x\n", (int)buf[3],
Sagar Dharia71fcea52012-09-12 23:21:57 -0600951 buf[4]);
952 txn->ec = -EIO;
953 }
954 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700955 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600956 complete(txn->comp);
957 }
958}
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700959
Sagar Dhariab94aa312014-01-14 17:36:32 -0700960static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart)
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700961{
Sagar Dharia33beca02012-10-22 16:21:46 -0600962 void __iomem *ngd;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600963 int timeout, ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -0600964 enum msm_ctrl_state cur_state = dev->state;
965 u32 laddr;
Sagar Dharia24419e32013-01-14 17:56:32 -0700966 u32 ngd_int = (NGD_INT_TX_NACKED_2 |
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700967 NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
968 NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
969 NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
Sagar Dharia33beca02012-10-22 16:21:46 -0600970
Sagar Dhariab94aa312014-01-14 17:36:32 -0700971 if (!mdm_restart && cur_state == MSM_CTRL_DOWN) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600972 int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
973 HZ);
974 if (!timeout)
Kiran Gundab27683f2014-01-07 15:58:31 +0530975 SLIM_ERR(dev, "slimbus QMI init timed out\n");
Sagar Dharia33beca02012-10-22 16:21:46 -0600976 }
977
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600978 /* No need to vote if contorller is not in low power mode */
Sagar Dhariab94aa312014-01-14 17:36:32 -0700979 if (!mdm_restart &&
980 (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP)) {
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600981 ret = msm_slim_qmi_power_request(dev, true);
982 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530983 SLIM_ERR(dev, "SLIM QMI power request failed:%d\n",
984 ret);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600985 return ret;
986 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600987 }
988 if (!dev->ver) {
989 dev->ver = readl_relaxed(dev->base);
990 /* Version info in 16 MSbits */
991 dev->ver >>= 16;
992 }
993 ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
994 laddr = readl_relaxed(ngd + NGD_STATUS);
995 if (laddr & NGD_LADDR) {
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700996 /*
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600997 * external MDM restart case where ADSP itself was active framer
998 * For example, modem restarted when playback was active
999 */
1000 if (cur_state == MSM_CTRL_AWAKE) {
Kiran Gundab27683f2014-01-07 15:58:31 +05301001 SLIM_INFO(dev, "Subsys restart: ADSP active framer\n");
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001002 return 0;
1003 }
1004 /*
Sagar Dharia33beca02012-10-22 16:21:46 -06001005 * ADSP power collapse case, where HW wasn't reset.
1006 * Reconnect BAM pipes if disconnected
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001007 */
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001008 ngd_slim_setup_msg_path(dev);
Sagar Dharia33beca02012-10-22 16:21:46 -06001009 return 0;
Sagar Dhariab94aa312014-01-14 17:36:32 -07001010 }
1011
1012 if (mdm_restart) {
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001013 /*
Sagar Dhariab94aa312014-01-14 17:36:32 -07001014 * external MDM SSR when MDM is active framer
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001015 * ADSP will reset slimbus HW. disconnect BAM pipes so that
1016 * they can be connected after capability message is received.
1017 * Set device state to ASLEEP to be synchronous with the HW
1018 */
Sagar Dhariab94aa312014-01-14 17:36:32 -07001019 /* make current state as DOWN */
1020 cur_state = MSM_CTRL_DOWN;
Kiran Gundab27683f2014-01-07 15:58:31 +05301021 SLIM_INFO(dev,
1022 "SLIM MDM restart: MDM active framer: reinit HW\n");
Sagar Dhariab94aa312014-01-14 17:36:32 -07001023 /* disconnect BAM pipes */
1024 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
1025 dev->use_rx_msgqs = MSM_MSGQ_DOWN;
1026 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
1027 dev->use_tx_msgqs = MSM_MSGQ_DOWN;
1028 dev->state = MSM_CTRL_DOWN;
Sagar Dharia33beca02012-10-22 16:21:46 -06001029 }
Sagar Dhariab94aa312014-01-14 17:36:32 -07001030 /* SSR scenario, need to disconnect pipe before connecting */
Sagar Dhariada48bd62013-03-21 18:02:40 -06001031 if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
1032 struct msm_slim_endp *endpoint = &dev->rx_msgq;
1033 sps_disconnect(endpoint->sps);
1034 sps_free_endpoint(endpoint->sps);
1035 dev->use_rx_msgqs = MSM_MSGQ_RESET;
1036 }
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001037 if (dev->use_tx_msgqs == MSM_MSGQ_DOWN) {
1038 struct msm_slim_endp *endpoint = &dev->tx_msgq;
1039 sps_disconnect(endpoint->sps);
1040 sps_free_endpoint(endpoint->sps);
1041 dev->use_tx_msgqs = MSM_MSGQ_RESET;
1042 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001043 /*
1044 * ADSP power collapse case (OR SSR), where HW was reset
1045 * BAM programming will happen when capability message is received
1046 */
1047 writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001048 NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -06001049 /*
1050 * Enable NGD. Configure NGD in register acc. mode until master
1051 * announcement is received
1052 */
Sagar Dharia24419e32013-01-14 17:56:32 -07001053 writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -06001054 /* make sure NGD enabling goes through */
1055 mb();
1056
1057 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
1058 if (!timeout) {
Kiran Gundab27683f2014-01-07 15:58:31 +05301059 SLIM_ERR(dev, "Failed to receive master capability\n");
Sagar Dharia33beca02012-10-22 16:21:46 -06001060 return -ETIMEDOUT;
1061 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301062 if (cur_state == MSM_CTRL_DOWN) {
Sagar Dharia33beca02012-10-22 16:21:46 -06001063 complete(&dev->ctrl_up);
Kiran Gundab27683f2014-01-07 15:58:31 +05301064 /* Resetting the log level */
1065 SLIM_RST_LOGLVL(dev);
1066 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001067 return 0;
1068}
1069
1070static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
1071{
1072 int ret = 0;
1073 if (enable) {
1074 ret = msm_slim_qmi_init(dev, false);
1075 /* controller state should be in sync with framework state */
1076 if (!ret) {
1077 ret = slim_ctrl_clk_pause(&dev->ctrl, false,
1078 SLIM_CLK_UNSPECIFIED);
1079 complete(&dev->qmi.qmi_comp);
1080 /*
1081 * Power-up won't be called if clock pause failed.
1082 * This can happen if ADSP SSR happened when audio
1083 * session is in progress. Framework will think that
1084 * clock pause failed so no need to wakeup controller.
1085 * Call power-up explicitly in that case, since slimbus
1086 * HW needs to be powered-on to be in sync with
1087 * framework state
1088 */
1089 if (ret)
Sagar Dhariab94aa312014-01-14 17:36:32 -07001090 ngd_slim_power_up(dev, false);
Sagar Dharia33beca02012-10-22 16:21:46 -06001091 if (!pm_runtime_enabled(dev->dev) ||
1092 !pm_runtime_suspended(dev->dev))
1093 ngd_slim_runtime_resume(dev->dev);
1094 else
1095 pm_runtime_resume(dev->dev);
1096 pm_runtime_mark_last_busy(dev->dev);
1097 pm_runtime_put(dev->dev);
1098 } else
Kiran Gundab27683f2014-01-07 15:58:31 +05301099 SLIM_ERR(dev, "qmi init fail, ret:%d, state:%d\n",
Sagar Dharia33beca02012-10-22 16:21:46 -06001100 ret, dev->state);
1101 } else {
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001102 msm_slim_qmi_exit(dev);
1103 }
1104
Sagar Dharia33beca02012-10-22 16:21:46 -06001105 return ret;
1106}
1107
1108static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
1109{
1110 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dhariab94aa312014-01-14 17:36:32 -07001111 return ngd_slim_power_up(dev, false);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001112}
1113
Sagar Dharia71fcea52012-09-12 23:21:57 -06001114static int ngd_slim_rx_msgq_thread(void *data)
1115{
1116 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
1117 struct completion *notify = &dev->rx_msgq_notify;
1118 int ret = 0, index = 0;
1119 u32 mc = 0;
1120 u32 mt = 0;
1121 u32 buffer[10];
1122 u8 msg_len = 0;
1123
1124 while (!kthread_should_stop()) {
1125 set_current_state(TASK_INTERRUPTIBLE);
Kiran Gundabbb3e312014-03-17 16:11:40 +05301126 wait_for_completion(notify);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001127 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -07001128 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001129 msm_slim_rx_dequeue(dev, (u8 *)buffer);
1130 ngd_slim_rx(dev, (u8 *)buffer);
1131 continue;
1132 }
1133 ret = msm_slim_rx_msgq_get(dev, buffer, index);
1134 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +05301135 SLIM_ERR(dev, "rx_msgq_get() failed 0x%x\n", ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001136 continue;
1137 }
1138
1139 /* Wait for complete message */
1140 if (index++ == 0) {
1141 msg_len = *buffer & 0x1F;
1142 mt = (buffer[0] >> 5) & 0x7;
1143 mc = (buffer[0] >> 8) & 0xff;
1144 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
1145 }
1146 if ((index * 4) >= msg_len) {
1147 index = 0;
1148 ngd_slim_rx(dev, (u8 *)buffer);
1149 } else
1150 continue;
1151 }
1152 return 0;
1153}
1154
Sagar Dhariae44cc822014-02-07 21:32:34 -07001155static int ngd_notify_slaves(void *data)
Sagar Dharia33beca02012-10-22 16:21:46 -06001156{
Sagar Dhariae44cc822014-02-07 21:32:34 -07001157 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
Sagar Dharia33beca02012-10-22 16:21:46 -06001158 struct slim_controller *ctrl = &dev->ctrl;
1159 struct slim_device *sbdev;
Sagar Dharia21f88552014-02-07 00:10:37 -07001160 struct list_head *pos, *next;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001161 int ret, i = 0;
1162 while (!kthread_should_stop()) {
1163 set_current_state(TASK_INTERRUPTIBLE);
Kiran Gundabbb3e312014-03-17 16:11:40 +05301164 wait_for_completion(&dev->qmi.slave_notify);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001165 /* Probe devices for first notification */
1166 if (!i) {
Kiran Gunda2b457b02014-04-04 14:58:56 +05301167 i++;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001168 dev->err = 0;
1169 if (dev->dev->of_node)
1170 of_register_slim_devices(&dev->ctrl);
1171
1172 /*
1173 * Add devices registered with board-info now that
1174 * controller is up
1175 */
1176 slim_ctrl_add_boarddevs(&dev->ctrl);
1177 } else {
1178 slim_framer_booted(ctrl);
1179 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001180 mutex_lock(&ctrl->m_ctrl);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001181 list_for_each_safe(pos, next, &ctrl->devs) {
Kiran Gunda2b457b02014-04-04 14:58:56 +05301182 int j;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001183 sbdev = list_entry(pos, struct slim_device, dev_list);
1184 mutex_unlock(&ctrl->m_ctrl);
Kiran Gunda2b457b02014-04-04 14:58:56 +05301185 for (j = 0; j < LADDR_RETRY; j++) {
Sagar Dhariae44cc822014-02-07 21:32:34 -07001186 ret = slim_get_logical_addr(sbdev,
1187 sbdev->e_addr,
1188 6, &sbdev->laddr);
1189 if (!ret)
1190 break;
1191 else /* time for ADSP to assign LA */
1192 msleep(20);
1193 }
1194 mutex_lock(&ctrl->m_ctrl);
1195 }
1196 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia33beca02012-10-22 16:21:46 -06001197 }
Sagar Dhariae44cc822014-02-07 21:32:34 -07001198 return 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001199}
1200
1201static void ngd_adsp_down(struct work_struct *work)
1202{
1203 struct msm_slim_qmi *qmi =
1204 container_of(work, struct msm_slim_qmi, ssr_down);
1205 struct msm_slim_ctrl *dev =
1206 container_of(qmi, struct msm_slim_ctrl, qmi);
1207 struct slim_controller *ctrl = &dev->ctrl;
1208 struct slim_device *sbdev;
Sagar Dharia33beca02012-10-22 16:21:46 -06001209
1210 ngd_slim_enable(dev, false);
1211 /* disconnect BAM pipes */
Sagar Dhariada48bd62013-03-21 18:02:40 -06001212 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
1213 dev->use_rx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001214 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
1215 dev->use_tx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia33beca02012-10-22 16:21:46 -06001216 msm_slim_sps_exit(dev, false);
Sagar Dharia33beca02012-10-22 16:21:46 -06001217 /* device up should be called again after SSR */
1218 list_for_each_entry(sbdev, &ctrl->devs, dev_list)
Sagar Dhariaf68d71f2013-07-31 17:43:46 -06001219 slim_report_absent(sbdev);
Kiran Gundab27683f2014-01-07 15:58:31 +05301220 SLIM_INFO(dev, "SLIM ADSP SSR (DOWN) done\n");
Sagar Dharia33beca02012-10-22 16:21:46 -06001221}
1222
1223static void ngd_adsp_up(struct work_struct *work)
1224{
1225 struct msm_slim_qmi *qmi =
1226 container_of(work, struct msm_slim_qmi, ssr_up);
1227 struct msm_slim_ctrl *dev =
1228 container_of(qmi, struct msm_slim_ctrl, qmi);
1229 ngd_slim_enable(dev, true);
1230}
1231
Kiran Gundab27683f2014-01-07 15:58:31 +05301232static ssize_t show_mask(struct device *device, struct device_attribute *attr,
1233 char *buf)
1234{
1235 struct platform_device *pdev = to_platform_device(device);
1236 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1237 return snprintf(buf, sizeof(int), "%u\n", dev->ipc_log_mask);
1238}
1239
1240static ssize_t set_mask(struct device *device, struct device_attribute *attr,
1241 const char *buf, size_t count)
1242{
1243 struct platform_device *pdev = to_platform_device(device);
1244 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1245
1246 dev->ipc_log_mask = buf[0] - '0';
1247 if (dev->ipc_log_mask > DBG_LEV)
1248 dev->ipc_log_mask = DBG_LEV;
1249 return count;
1250}
1251
1252static DEVICE_ATTR(debug_mask, S_IRUGO | S_IWUSR, show_mask, set_mask);
1253
Sagar Dharia71fcea52012-09-12 23:21:57 -06001254static int __devinit ngd_slim_probe(struct platform_device *pdev)
1255{
1256 struct msm_slim_ctrl *dev;
1257 int ret;
1258 struct resource *bam_mem;
1259 struct resource *slim_mem;
1260 struct resource *irq, *bam_irq;
Sagar Dharia24419e32013-01-14 17:56:32 -07001261 bool rxreg_access = false;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001262 bool slim_mdm = false;
Naveen Kaje284da552014-03-26 09:54:29 -06001263 const char *ext_modem_id = NULL;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001264
Sagar Dharia71fcea52012-09-12 23:21:57 -06001265 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1266 "slimbus_physical");
1267 if (!slim_mem) {
1268 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1269 return -ENODEV;
1270 }
1271 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1272 "slimbus_bam_physical");
1273 if (!bam_mem) {
1274 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1275 return -ENODEV;
1276 }
1277 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1278 "slimbus_irq");
1279 if (!irq) {
1280 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1281 return -ENODEV;
1282 }
1283 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1284 "slimbus_bam_irq");
1285 if (!bam_irq) {
1286 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1287 return -ENODEV;
1288 }
1289
1290 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
Kiran Gunda318cac42013-10-21 17:00:15 +05301291 if (IS_ERR_OR_NULL(dev)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001292 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1293 return PTR_ERR(dev);
1294 }
1295 dev->dev = &pdev->dev;
1296 platform_set_drvdata(pdev, dev);
1297 slim_set_ctrldata(&dev->ctrl, dev);
Kiran Gundab27683f2014-01-07 15:58:31 +05301298
1299 /* Create IPC log context */
1300 dev->ipc_slimbus_log = ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES,
1301 dev_name(dev->dev));
1302 if (!dev->ipc_slimbus_log)
1303 dev_err(&pdev->dev, "error creating ipc_logging context\n");
1304 else {
1305 /* Initialize the log mask */
1306 dev->ipc_log_mask = INFO_LEV;
1307 dev->default_ipc_log_mask = INFO_LEV;
1308 SLIM_INFO(dev, "start logging for slim dev %s\n",
1309 dev_name(dev->dev));
1310 }
1311 ret = sysfs_create_file(&dev->dev->kobj, &dev_attr_debug_mask.attr);
1312 if (ret) {
1313 dev_err(&pdev->dev, "Failed to create dev. attr\n");
1314 dev->sysfs_created = false;
1315 } else
1316 dev->sysfs_created = true;
1317
Sagar Dharia71fcea52012-09-12 23:21:57 -06001318 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1319 if (!dev->base) {
1320 dev_err(&pdev->dev, "IOremap failed\n");
1321 ret = -ENOMEM;
1322 goto err_ioremap_failed;
1323 }
1324 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1325 if (!dev->bam.base) {
1326 dev_err(&pdev->dev, "BAM IOremap failed\n");
1327 ret = -ENOMEM;
1328 goto err_ioremap_bam_failed;
1329 }
1330 if (pdev->dev.of_node) {
1331
1332 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1333 &dev->ctrl.nr);
1334 if (ret) {
1335 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1336 goto err_ctrl_failed;
1337 }
Sagar Dharia24419e32013-01-14 17:56:32 -07001338 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1339 "qcom,rxreg-access");
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001340 of_property_read_u32(pdev->dev.of_node, "qcom,apps-ch-pipes",
1341 &dev->pdata.apps_pipes);
1342 of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
1343 &dev->pdata.eapc);
Naveen Kaje284da552014-03-26 09:54:29 -06001344 ret = of_property_read_string(pdev->dev.of_node,
1345 "qcom,slim-mdm", &ext_modem_id);
1346 if (!ret)
1347 slim_mdm = true;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001348 } else {
1349 dev->ctrl.nr = pdev->id;
1350 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001351 /*
1352 * Keep PGD's logical address as manager's. Query it when first data
1353 * channel request comes in
1354 */
1355 dev->pgdla = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001356 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1357 dev->ctrl.nports = MSM_SLIM_NPORTS;
1358 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1359 dev->framer.superfreq =
1360 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1361 dev->ctrl.a_framer = &dev->framer;
1362 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
1363 dev->ctrl.set_laddr = ngd_set_laddr;
1364 dev->ctrl.get_laddr = ngd_get_laddr;
1365 dev->ctrl.allocbw = ngd_allocbw;
1366 dev->ctrl.xfer_msg = ngd_xfer_msg;
Sagar Dhariab046b3c2014-01-27 21:30:48 -07001367 dev->ctrl.xfer_user_msg = ngd_user_msg;
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001368 dev->ctrl.wakeup = ngd_clk_pause_wakeup;
Sagar Dharia100e7212013-05-17 18:20:57 -06001369 dev->ctrl.alloc_port = msm_alloc_port;
1370 dev->ctrl.dealloc_port = msm_dealloc_port;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001371 dev->ctrl.port_xfer = msm_slim_port_xfer;
1372 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001373 dev->bam_mem = bam_mem;
1374
1375 init_completion(&dev->reconf);
Sagar Dharia33beca02012-10-22 16:21:46 -06001376 init_completion(&dev->ctrl_up);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001377 mutex_init(&dev->tx_lock);
1378 spin_lock_init(&dev->rx_lock);
1379 dev->ee = 1;
1380 dev->irq = irq->start;
1381 dev->bam.irq = bam_irq->start;
1382
Sagar Dharia24419e32013-01-14 17:56:32 -07001383 if (rxreg_access)
1384 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
1385 else
1386 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001387
1388 /* Enable TX message queues by default as recommended by HW */
1389 dev->use_tx_msgqs = MSM_MSGQ_RESET;
1390
Sagar Dharia71fcea52012-09-12 23:21:57 -06001391 init_completion(&dev->rx_msgq_notify);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001392 init_completion(&dev->qmi.slave_notify);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001393
1394 /* Register with framework */
1395 ret = slim_add_numbered_controller(&dev->ctrl);
1396 if (ret) {
1397 dev_err(dev->dev, "error adding controller\n");
1398 goto err_ctrl_failed;
1399 }
1400
1401 dev->ctrl.dev.parent = &pdev->dev;
1402 dev->ctrl.dev.of_node = pdev->dev.of_node;
Sagar Dharia33beca02012-10-22 16:21:46 -06001403 dev->state = MSM_CTRL_DOWN;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001404
1405 ret = request_irq(dev->irq, ngd_slim_interrupt,
1406 IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
1407
1408 if (ret) {
1409 dev_err(&pdev->dev, "request IRQ failed\n");
1410 goto err_request_irq_failed;
1411 }
1412
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001413 init_completion(&dev->qmi.qmi_comp);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001414 dev->err = -EPROBE_DEFER;
Sagar Dharia33beca02012-10-22 16:21:46 -06001415 pm_runtime_use_autosuspend(dev->dev);
1416 pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
1417 pm_runtime_set_suspended(dev->dev);
1418 pm_runtime_enable(dev->dev);
1419
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001420 if (slim_mdm) {
1421 dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
Naveen Kaje284da552014-03-26 09:54:29 -06001422 dev->mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001423 &dev->mdm.nb);
1424 if (IS_ERR_OR_NULL(dev->mdm.ssr))
1425 dev_err(dev->dev,
1426 "subsys_notif_register_notifier failed %p",
1427 dev->mdm.ssr);
1428 }
1429
Sagar Dharia33beca02012-10-22 16:21:46 -06001430 INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
1431 INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001432 dev->qmi.nb.notifier_call = ngd_qmi_available;
Sagar Dharia33beca02012-10-22 16:21:46 -06001433 pm_runtime_get_noresume(dev->dev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001434 ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001435 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001436 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1437 if (ret) {
1438 pr_err("Slimbus QMI service registration failed:%d", ret);
1439 goto qmi_register_failed;
1440 }
1441
Sagar Dharia33beca02012-10-22 16:21:46 -06001442
Sagar Dharia71fcea52012-09-12 23:21:57 -06001443 /* Fire up the Rx message queue thread */
1444 dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
Sagar Dhariae44cc822014-02-07 21:32:34 -07001445 "ngd_rx_thread%d", dev->ctrl.nr);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001446 if (IS_ERR(dev->rx_msgq_thread)) {
1447 ret = PTR_ERR(dev->rx_msgq_thread);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001448 dev_err(dev->dev, "Failed to start Rx thread:%d\n", ret);
1449 goto err_rx_thread_create_failed;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001450 }
1451
Sagar Dhariae44cc822014-02-07 21:32:34 -07001452 /* Start thread to probe, and notify slaves */
1453 dev->qmi.slave_thread = kthread_run(ngd_notify_slaves, dev,
1454 "ngd_notify_sl%d", dev->ctrl.nr);
1455 if (IS_ERR(dev->qmi.slave_thread)) {
1456 ret = PTR_ERR(dev->qmi.slave_thread);
1457 dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
1458 goto err_notify_thread_create_failed;
1459 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301460 SLIM_INFO(dev, "NGD SB controller is up!\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001461 return 0;
1462
Sagar Dhariae44cc822014-02-07 21:32:34 -07001463err_notify_thread_create_failed:
1464 kthread_stop(dev->rx_msgq_thread);
1465err_rx_thread_create_failed:
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001466 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001467 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001468 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1469qmi_register_failed:
Sagar Dharia71fcea52012-09-12 23:21:57 -06001470 free_irq(dev->irq, dev);
1471err_request_irq_failed:
1472 slim_del_controller(&dev->ctrl);
1473err_ctrl_failed:
1474 iounmap(dev->bam.base);
1475err_ioremap_bam_failed:
1476 iounmap(dev->base);
1477err_ioremap_failed:
Kiran Gundab27683f2014-01-07 15:58:31 +05301478 if (dev->sysfs_created)
1479 sysfs_remove_file(&dev->dev->kobj,
1480 &dev_attr_debug_mask.attr);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001481 kfree(dev);
1482 return ret;
1483}
1484
1485static int __devexit ngd_slim_remove(struct platform_device *pdev)
1486{
1487 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001488 ngd_slim_enable(dev, false);
Kiran Gundab27683f2014-01-07 15:58:31 +05301489 if (dev->sysfs_created)
1490 sysfs_remove_file(&dev->dev->kobj,
1491 &dev_attr_debug_mask.attr);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001492 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001493 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001494 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001495 pm_runtime_disable(&pdev->dev);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001496 if (!IS_ERR_OR_NULL(dev->mdm.ssr))
1497 subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001498 free_irq(dev->irq, dev);
1499 slim_del_controller(&dev->ctrl);
1500 kthread_stop(dev->rx_msgq_thread);
1501 iounmap(dev->bam.base);
1502 iounmap(dev->base);
1503 kfree(dev);
1504 return 0;
1505}
1506
1507#ifdef CONFIG_PM_RUNTIME
1508static int ngd_slim_runtime_idle(struct device *device)
1509{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001510 struct platform_device *pdev = to_platform_device(device);
1511 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1512 if (dev->state == MSM_CTRL_AWAKE)
1513 dev->state = MSM_CTRL_IDLE;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001514 dev_dbg(device, "pm_runtime: idle...\n");
1515 pm_request_autosuspend(device);
1516 return -EAGAIN;
1517}
1518#endif
1519
1520/*
1521 * If PM_RUNTIME is not defined, these 2 functions become helper
1522 * functions to be called from system suspend/resume. So they are not
1523 * inside ifdef CONFIG_PM_RUNTIME
1524 */
Sagar Dharia71fcea52012-09-12 23:21:57 -06001525static int ngd_slim_runtime_resume(struct device *device)
1526{
1527 struct platform_device *pdev = to_platform_device(device);
1528 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1529 int ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001530 if (dev->state >= MSM_CTRL_ASLEEP)
Sagar Dharia71fcea52012-09-12 23:21:57 -06001531 ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
1532 if (ret) {
Sagar Dharia129c7d82013-08-08 19:35:50 -06001533 /* Did SSR cause this clock pause failure */
1534 if (dev->state != MSM_CTRL_DOWN)
1535 dev->state = MSM_CTRL_ASLEEP;
1536 else
Kiran Gundab27683f2014-01-07 15:58:31 +05301537 SLIM_WARN(dev, "HW wakeup attempt during SSR\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001538 } else {
1539 dev->state = MSM_CTRL_AWAKE;
1540 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301541 SLIM_INFO(dev, "Slim runtime resume: ret %d\n", ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001542 return ret;
1543}
1544
Sagar Dharia33beca02012-10-22 16:21:46 -06001545#ifdef CONFIG_PM_SLEEP
1546static int ngd_slim_runtime_suspend(struct device *device)
1547{
1548 struct platform_device *pdev = to_platform_device(device);
1549 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1550 int ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001551 ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
1552 if (ret) {
1553 if (ret != -EBUSY)
Kiran Gundab27683f2014-01-07 15:58:31 +05301554 SLIM_INFO(dev, "clk pause not entered:%d\n", ret);
Sagar Dharia33beca02012-10-22 16:21:46 -06001555 dev->state = MSM_CTRL_AWAKE;
1556 } else {
1557 dev->state = MSM_CTRL_ASLEEP;
1558 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301559 SLIM_INFO(dev, "Slim runtime suspend: ret %d\n", ret);
Sagar Dharia33beca02012-10-22 16:21:46 -06001560 return ret;
1561}
1562
Sagar Dharia71fcea52012-09-12 23:21:57 -06001563static int ngd_slim_suspend(struct device *dev)
1564{
1565 int ret = -EBUSY;
Sagar Dhariad1468b72013-07-16 12:56:22 -06001566 struct platform_device *pdev = to_platform_device(dev);
1567 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
1568 if (!pm_runtime_enabled(dev) ||
1569 (!pm_runtime_suspended(dev) &&
1570 cdev->state == MSM_CTRL_IDLE)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001571 ret = ngd_slim_runtime_suspend(dev);
Sagar Dhariaa1398282013-01-22 13:26:20 -07001572 /*
1573 * If runtime-PM still thinks it's active, then make sure its
1574 * status is in sync with HW status.
1575 * Since this suspend calls QMI api, it results in holding a
1576 * wakelock. That results in failure of first suspend.
1577 * Subsequent suspend should not call low-power transition
1578 * again since the HW is already in suspended state.
1579 */
1580 if (!ret) {
1581 pm_runtime_disable(dev);
1582 pm_runtime_set_suspended(dev);
1583 pm_runtime_enable(dev);
1584 }
Sagar Dharia71fcea52012-09-12 23:21:57 -06001585 }
1586 if (ret == -EBUSY) {
1587 /*
1588 * There is a possibility that some audio stream is active
1589 * during suspend. We dont want to return suspend failure in
1590 * that case so that display and relevant components can still
1591 * go to suspend.
1592 * If there is some other error, then it should be passed-on
1593 * to system level suspend
1594 */
1595 ret = 0;
1596 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301597 SLIM_INFO(cdev, "system suspend\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001598 return ret;
1599}
1600
1601static int ngd_slim_resume(struct device *dev)
1602{
Kiran Gundab27683f2014-01-07 15:58:31 +05301603 struct platform_device *pdev = to_platform_device(dev);
1604 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
Sagar Dhariaa1398282013-01-22 13:26:20 -07001605 /*
1606 * Rely on runtime-PM to call resume in case it is enabled.
1607 * Even if it's not enabled, rely on 1st client transaction to do
1608 * clock/power on
1609 */
Kiran Gundab27683f2014-01-07 15:58:31 +05301610 SLIM_INFO(cdev, "system resume\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001611 return 0;
1612}
1613#endif /* CONFIG_PM_SLEEP */
1614
1615static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
1616 SET_SYSTEM_SLEEP_PM_OPS(
1617 ngd_slim_suspend,
1618 ngd_slim_resume
1619 )
1620 SET_RUNTIME_PM_OPS(
1621 ngd_slim_runtime_suspend,
1622 ngd_slim_runtime_resume,
1623 ngd_slim_runtime_idle
1624 )
1625};
1626
1627static struct of_device_id ngd_slim_dt_match[] = {
1628 {
1629 .compatible = "qcom,slim-ngd",
1630 },
1631 {}
1632};
1633
1634static struct platform_driver ngd_slim_driver = {
1635 .probe = ngd_slim_probe,
1636 .remove = ngd_slim_remove,
1637 .driver = {
1638 .name = NGD_SLIM_NAME,
1639 .owner = THIS_MODULE,
1640 .pm = &ngd_slim_dev_pm_ops,
1641 .of_match_table = ngd_slim_dt_match,
1642 },
1643};
1644
1645static int ngd_slim_init(void)
1646{
1647 return platform_driver_register(&ngd_slim_driver);
1648}
1649late_initcall(ngd_slim_init);
1650
1651static void ngd_slim_exit(void)
1652{
1653 platform_driver_unregister(&ngd_slim_driver);
1654}
1655module_exit(ngd_slim_exit);
1656
1657MODULE_LICENSE("GPL v2");
1658MODULE_DESCRIPTION("MSM Slimbus controller");
1659MODULE_ALIAS("platform:msm-slim-ngd");