blob: b4c88cdf4c45f92326a2553f0815547d6cd8ab86 [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 Dharia9bd4c712014-04-30 18:36:17 -0600304
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700305 else if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
Sagar Dharia9bd4c712014-04-30 18:36:17 -0600306 return -EPROTONOSUPPORT;
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700307
Sagar Dharia71fcea52012-09-12 23:21:57 -0600308 if (txn->mt == SLIM_MSG_MT_CORE &&
309 (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
310 txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
311 return 0;
312 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600313 /* If txn is tried when controller is down, wait for ADSP to boot */
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700314 if (!report_sat) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600315 if (dev->state == MSM_CTRL_DOWN) {
316 u8 mc = (u8)txn->mc;
317 int timeout;
Kiran Gundab27683f2014-01-07 15:58:31 +0530318 SLIM_INFO(dev, "ADSP slimbus not up yet\n");
Sagar Dharia33beca02012-10-22 16:21:46 -0600319 /*
320 * Messages related to data channel management can't
321 * wait since they are holding reconfiguration lock.
322 * clk_pause in resume (which can change state back to
Sagar Dharia32379162013-12-12 00:46:37 -0700323 * MSM_CTRL_AWAKE), will need that lock.
324 * Port disconnection, channel removal calls should pass
325 * through since there is no activity on the bus and
326 * those calls are triggered by clients due to
327 * device_down callback in that situation.
328 * Returning 0 on the disconnections and
329 * removals will ensure consistent state of channels,
330 * ports with the HW
Sagar Dharia55bced82014-01-20 16:00:44 -0700331 * Remote requests to remove channel/port will be
332 * returned from the path where they wait on
333 * acknowledgement from ADSP
Sagar Dharia33beca02012-10-22 16:21:46 -0600334 */
Sagar Dharia32379162013-12-12 00:46:37 -0700335 if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
336 ((mc == SLIM_USR_MC_CHAN_CTRL ||
337 mc == SLIM_USR_MC_DISCONNECT_PORT ||
338 mc == SLIM_USR_MC_RECONFIG_NOW)))
Sagar Dharia55bced82014-01-20 16:00:44 -0700339 return -EREMOTEIO;
Sagar Dharia32379162013-12-12 00:46:37 -0700340 if ((txn->mt == SLIM_MSG_MT_CORE) &&
341 ((mc == SLIM_MSG_MC_DISCONNECT_PORT ||
342 mc == SLIM_MSG_MC_NEXT_REMOVE_CHANNEL ||
343 mc == SLIM_USR_MC_RECONFIG_NOW)))
344 return 0;
Sagar Dharia33beca02012-10-22 16:21:46 -0600345 if ((txn->mt == SLIM_MSG_MT_CORE) &&
346 ((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
347 mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
348 (mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
349 mc <= SLIM_MSG_MC_RECONFIGURE_NOW)))
350 return -EREMOTEIO;
351 if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
352 ((mc >= SLIM_USR_MC_DEFINE_CHAN &&
Sagar Dharia32379162013-12-12 00:46:37 -0700353 mc < SLIM_USR_MC_DISCONNECT_PORT)))
Sagar Dharia33beca02012-10-22 16:21:46 -0600354 return -EREMOTEIO;
355 timeout = wait_for_completion_timeout(&dev->ctrl_up,
356 HZ);
Sagar Dharia4f240722014-01-15 13:50:58 -0700357 if (!timeout && dev->state == MSM_CTRL_DOWN)
Sagar Dharia33beca02012-10-22 16:21:46 -0600358 return -ETIMEDOUT;
359 }
Sagar Dharia129c7d82013-08-08 19:35:50 -0600360 ret = msm_slim_get_ctrl(dev);
361 /*
362 * Runtime-pm's callbacks are not called until runtime-pm's
363 * error status is cleared
364 * Setting runtime status to suspended clears the error
365 * It also makes HW status cosistent with what SW has it here
366 */
367 if (ret == -ENETRESET && dev->state == MSM_CTRL_DOWN) {
368 pm_runtime_set_suspended(dev->dev);
369 msm_slim_put_ctrl(dev);
370 return -EREMOTEIO;
Sagar Dhariad1468b72013-07-16 12:56:22 -0600371 } else if (ret >= 0) {
372 dev->state = MSM_CTRL_AWAKE;
Sagar Dharia129c7d82013-08-08 19:35:50 -0600373 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600374 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600375 mutex_lock(&dev->tx_lock);
Sagar Dharia33beca02012-10-22 16:21:46 -0600376
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700377 if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530378 SLIM_ERR(dev, "controller not ready\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600379 mutex_unlock(&dev->tx_lock);
Sagar Dharia9bd4c712014-04-30 18:36:17 -0600380 pm_runtime_set_suspended(dev->dev);
Sagar Dharia33beca02012-10-22 16:21:46 -0600381 msm_slim_put_ctrl(dev);
382 return -EREMOTEIO;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600383 }
384 if (txn->mt == SLIM_MSG_MT_CORE &&
385 (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
386 txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
387 txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
388 int i = 0;
Kiran Gundab27683f2014-01-07 15:58:31 +0530389 if (txn->mc != SLIM_MSG_MC_DISCONNECT_PORT)
390 SLIM_INFO(dev,
391 "Connect port: laddr 0x%x port_num %d chan_num %d\n",
392 txn->la, txn->wbuf[0], txn->wbuf[1]);
393 else
394 SLIM_INFO(dev,
395 "Disconnect port: laddr 0x%x port_num %d\n",
396 txn->la, txn->wbuf[0]);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600397 txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
398 if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
399 txn->mc = SLIM_USR_MC_CONNECT_SRC;
400 else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
401 txn->mc = SLIM_USR_MC_CONNECT_SINK;
402 else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
403 txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600404 if (txn->la == SLIM_LA_MGR) {
405 if (dev->pgdla == SLIM_LA_MGR) {
406 u8 ea[] = {0, QC_DEVID_PGD, 0, 0, QC_MFGID_MSB,
407 QC_MFGID_LSB};
408 ea[2] = (u8)(dev->pdata.eapc & 0xFF);
409 ea[3] = (u8)((dev->pdata.eapc & 0xFF00) >> 8);
410 mutex_unlock(&dev->tx_lock);
411 ret = dev->ctrl.get_laddr(&dev->ctrl, ea, 6,
412 &dev->pgdla);
Kiran Gundab27683f2014-01-07 15:58:31 +0530413 SLIM_DBG(dev, "SLIM PGD LA:0x%x, ret:%d\n",
414 dev->pgdla, ret);
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600415 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530416 SLIM_ERR(dev,
417 "Incorrect SLIM-PGD EAPC:0x%x\n",
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600418 dev->pdata.eapc);
419 return ret;
420 }
421 mutex_lock(&dev->tx_lock);
422 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600423 txn->la = dev->pgdla;
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600424 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600425 wbuf[i++] = txn->la;
426 la = SLIM_LA_MGR;
427 wbuf[i++] = txn->wbuf[0];
428 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
429 wbuf[i++] = txn->wbuf[1];
430 ret = ngd_get_tid(ctrl, txn, &wbuf[i++], &done);
431 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530432 SLIM_ERR(dev, "TID for connect/disconnect fail:%d\n",
433 ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600434 goto ngd_xfer_err;
435 }
436 txn->len = i;
437 txn->wbuf = wbuf;
438 txn->rl = txn->len + 4;
439 }
440 txn->rl--;
441 pbuf = msm_get_msg_buf(dev, txn->rl);
442 if (!pbuf) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530443 SLIM_ERR(dev, "Message buffer unavailable\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600444 ret = -ENOMEM;
445 goto ngd_xfer_err;
446 }
447 dev->err = 0;
448
449 if (txn->dt == SLIM_MSG_DEST_ENUMADDR) {
450 ret = -EPROTONOSUPPORT;
451 goto ngd_xfer_err;
452 }
453 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
454 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
455 la);
456 else
457 *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
458 la);
459 if (txn->dt == SLIM_MSG_DEST_LOGICALADDR)
460 puc = ((u8 *)pbuf) + 3;
461 else
462 puc = ((u8 *)pbuf) + 2;
463 if (txn->rbuf)
464 *(puc++) = txn->tid;
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700465 if (((txn->mt == SLIM_MSG_MT_CORE) &&
Sagar Dharia71fcea52012-09-12 23:21:57 -0600466 ((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
467 txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
468 (txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700469 txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) ||
470 (txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
471 txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600472 *(puc++) = (txn->ec & 0xFF);
473 *(puc++) = (txn->ec >> 8)&0xFF;
474 }
475 if (txn->wbuf)
476 memcpy(puc, txn->wbuf, txn->len);
477 if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
478 (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
479 txn->mc == SLIM_USR_MC_CONNECT_SINK ||
480 txn->mc == SLIM_USR_MC_DISCONNECT_PORT) && txn->wbuf &&
481 wbuf[0] == dev->pgdla) {
Sagar Dharia2d74c142013-05-17 02:24:06 -0600482 if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600483 dev->err = msm_slim_connect_pipe_port(dev, wbuf[1]);
484 else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600485 /*
486 * Remove channel disconnects master-side ports from
487 * channel. No need to send that again on the bus
Sagar Dharia2d74c142013-05-17 02:24:06 -0600488 * Only disable port
Sagar Dharia71fcea52012-09-12 23:21:57 -0600489 */
Sagar Dharia2d74c142013-05-17 02:24:06 -0600490 writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn,
491 (wbuf[1] + dev->port_b), dev->ver));
Sagar Dharia71fcea52012-09-12 23:21:57 -0600492 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700493 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600494 return 0;
495 }
496 if (dev->err) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530497 SLIM_ERR(dev, "pipe-port connect err:%d\n", dev->err);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600498 goto ngd_xfer_err;
499 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -0600500 /* Add port-base to port number if this is manager side port */
501 puc[1] += dev->port_b;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600502 }
503 dev->err = 0;
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600504 /*
505 * If it's a read txn, it may be freed if a response is received by
506 * received thread before reaching end of this function.
507 * mc, mt may have changed to convert standard slimbus code/type to
508 * satellite user-defined message. Reinitialize again
509 */
510 txn_mc = txn->mc;
511 txn_mt = txn->mt;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600512 dev->wr_comp = &tx_sent;
513 ret = msm_send_msg_buf(dev, pbuf, txn->rl,
514 NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
515 if (!ret) {
516 int timeout = wait_for_completion_timeout(&tx_sent, HZ);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600517 if (!timeout) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600518 ret = -ETIMEDOUT;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600519 /*
520 * disconnect/recoonect pipe so that subsequent
521 * transactions don't timeout due to unavailable
522 * descriptors
523 */
524 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
525 &dev->use_tx_msgqs);
526 msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
527 } else {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600528 ret = dev->err;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600529 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600530 }
531 dev->wr_comp = NULL;
532 if (ret) {
533 u32 conf, stat, rx_msgq, int_stat, int_en, int_clr;
534 void __iomem *ngd = dev->base + NGD_BASE(dev->ctrl.nr,
535 dev->ver);
Kiran Gundab27683f2014-01-07 15:58:31 +0530536 SLIM_WARN(dev, "TX failed :MC:0x%x,mt:0x%x, ret:%d, ver:%d\n",
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600537 txn_mc, txn_mt, ret, dev->ver);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600538 conf = readl_relaxed(ngd);
539 stat = readl_relaxed(ngd + NGD_STATUS);
540 rx_msgq = readl_relaxed(ngd + NGD_RX_MSGQ_CFG);
541 int_stat = readl_relaxed(ngd + NGD_INT_STAT);
542 int_en = readl_relaxed(ngd + NGD_INT_EN);
543 int_clr = readl_relaxed(ngd + NGD_INT_CLR);
544
Kiran Gundab27683f2014-01-07 15:58:31 +0530545 SLIM_WARN(dev, "conf:0x%x,stat:0x%x,rxmsgq:0x%x\n",
546 conf, stat, rx_msgq);
547 SLIM_WARN(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
548 int_stat, int_en, int_clr);
Sagar Dharia8e554ed2013-07-19 15:48:15 -0600549 } else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
550 (txn_mc == SLIM_USR_MC_CONNECT_SRC ||
551 txn_mc == SLIM_USR_MC_CONNECT_SINK ||
552 txn_mc == SLIM_USR_MC_DISCONNECT_PORT)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600553 int timeout;
554 mutex_unlock(&dev->tx_lock);
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700555 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600556 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600557 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600558 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600559 else
560 ret = txn->ec;
561 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530562 SLIM_INFO(dev,
563 "connect/disconnect:0x%x,tid:%d err:%d\n",
564 txn->mc, txn->tid, ret);
Sagar Dhariad2959352012-12-01 15:43:01 -0700565 mutex_lock(&ctrl->m_ctrl);
566 ctrl->txnt[txn->tid] = NULL;
567 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600568 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600569 return ret ? ret : dev->err;
570 }
571ngd_xfer_err:
572 mutex_unlock(&dev->tx_lock);
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700573 if (!report_sat)
Sagar Dharia33beca02012-10-22 16:21:46 -0600574 msm_slim_put_ctrl(dev);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600575 return ret ? ret : dev->err;
576}
577
Sagar Dhariab046b3c2014-01-27 21:30:48 -0700578static int ngd_user_msg(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc,
579 struct slim_ele_access *msg, u8 *buf, u8 len)
580{
581 struct slim_msg_txn txn;
582
583 if (mt != SLIM_MSG_MT_DEST_REFERRED_USER ||
584 mc != SLIM_USR_MC_REPEAT_CHANGE_VALUE) {
585 return -EPROTONOSUPPORT;
586 }
587 if (len > SLIM_MAX_VE_SLC_BYTES ||
588 msg->start_offset > MSM_SLIM_VE_MAX_MAP_ADDR)
589 return -EINVAL;
590 if (len <= 4) {
591 txn.ec = len - 1;
592 } else if (len <= 8) {
593 if (len & 0x1)
594 return -EINVAL;
595 txn.ec = ((len >> 1) + 1);
596 } else {
597 if (len & 0x3)
598 return -EINVAL;
599 txn.ec = ((len >> 2) + 3);
600 }
601 txn.ec |= (0x8 | ((msg->start_offset & 0xF) << 4));
602 txn.ec |= ((msg->start_offset & 0xFF0) << 4);
603
604 txn.la = la;
605 txn.mt = mt;
606 txn.mc = mc;
607 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
608 txn.len = len;
609 txn.rl = len + 6;
610 txn.wbuf = buf;
611 txn.rbuf = NULL;
612 txn.comp = msg->comp;
613 return ngd_xfer_msg(ctrl, &txn);
614}
615
Sagar Dharia71fcea52012-09-12 23:21:57 -0600616static int ngd_xferandwait_ack(struct slim_controller *ctrl,
617 struct slim_msg_txn *txn)
618{
Kiran Gundab27683f2014-01-07 15:58:31 +0530619 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600620 int ret = ngd_xfer_msg(ctrl, txn);
621 if (!ret) {
622 int timeout;
623 timeout = wait_for_completion_timeout(txn->comp, HZ);
Sagar Dharia33beca02012-10-22 16:21:46 -0600624 if (!timeout)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600625 ret = -ETIMEDOUT;
Sagar Dharia33beca02012-10-22 16:21:46 -0600626 else
Sagar Dharia71fcea52012-09-12 23:21:57 -0600627 ret = txn->ec;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600628 }
Sagar Dharia55bced82014-01-20 16:00:44 -0700629
Sagar Dharia33beca02012-10-22 16:21:46 -0600630 if (ret) {
Sagar Dharia21f88552014-02-07 00:10:37 -0700631 if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
Kiran Gundab27683f2014-01-07 15:58:31 +0530632 SLIM_ERR(dev, "master msg:0x%x,tid:%d ret:%d\n",
633 txn->mc, txn->tid, ret);
Sagar Dharia33beca02012-10-22 16:21:46 -0600634 mutex_lock(&ctrl->m_ctrl);
635 ctrl->txnt[txn->tid] = NULL;
636 mutex_unlock(&ctrl->m_ctrl);
637 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600638
639 return ret;
640}
641
642static int ngd_allocbw(struct slim_device *sb, int *subfrmc, int *clkgear)
643{
Kiran Gundab27683f2014-01-07 15:58:31 +0530644 int ret = 0, num_chan = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600645 struct slim_pending_ch *pch;
646 struct slim_msg_txn txn;
647 struct slim_controller *ctrl = sb->ctrl;
648 DECLARE_COMPLETION_ONSTACK(done);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600649 u8 wbuf[SLIM_MSGQ_BUF_LEN];
Kiran Gundab27683f2014-01-07 15:58:31 +0530650 struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600651
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600652 *clkgear = ctrl->clkgear;
653 *subfrmc = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600654 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
655 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
656 txn.la = SLIM_LA_MGR;
657 txn.len = 0;
658 txn.ec = 0;
659 txn.wbuf = wbuf;
660 txn.rbuf = NULL;
661
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600662 if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530663 SLIM_DBG(dev, "slim reserve BW for messaging: req: %d\n",
Sagar Dharia5ee34ae2013-04-26 18:05:37 -0600664 ctrl->sched.pending_msgsl);
665 txn.mc = SLIM_USR_MC_REQ_BW;
666 wbuf[txn.len++] = ((sb->laddr & 0x1f) |
667 ((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
668 wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
669 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
670 if (ret)
671 return ret;
672 txn.rl = txn.len + 4;
673 ret = ngd_xferandwait_ack(ctrl, &txn);
674 if (ret)
675 return ret;
676
677 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
678 txn.len = 2;
679 wbuf[1] = sb->laddr;
680 txn.rl = txn.len + 4;
681 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
682 if (ret)
683 return ret;
684 ret = ngd_xferandwait_ack(ctrl, &txn);
685 if (ret)
686 return ret;
687
688 txn.len = 0;
689 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600690 list_for_each_entry(pch, &sb->mark_define, pending) {
691 struct slim_ich *slc;
692 slc = &ctrl->chans[pch->chan];
693 if (!slc) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530694 SLIM_WARN(dev, "no channel in define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600695 return -ENXIO;
696 }
697 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600698 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600699 wbuf[txn.len++] = (u8) (slc->prop.dataf << 5) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600700 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600701 wbuf[txn.len] = slc->seglen;
702 if (slc->coeff == SLIM_COEFF_3)
703 wbuf[txn.len] |= 1 << 5;
704 wbuf[txn.len++] |= slc->prop.auxf << 6;
705 wbuf[txn.len++] = slc->rootexp << 4 | slc->prop.prot;
706 wbuf[txn.len++] = slc->prrate;
707 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
708 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530709 SLIM_WARN(dev, "no tid for channel define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600710 return -ENXIO;
711 }
712 }
Kiran Gundab27683f2014-01-07 15:58:31 +0530713 num_chan++;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600714 wbuf[txn.len++] = slc->chan;
Kiran Gundab27683f2014-01-07 15:58:31 +0530715 SLIM_INFO(dev, "slim activate chan:%d, laddr: 0x%x\n",
716 slc->chan, sb->laddr);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600717 }
718 if (txn.len) {
719 txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
720 txn.rl = txn.len + 4;
721 ret = ngd_xferandwait_ack(ctrl, &txn);
722 if (ret)
723 return ret;
724
725 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
726 txn.len = 2;
727 wbuf[1] = sb->laddr;
728 txn.rl = txn.len + 4;
729 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
730 if (ret)
731 return ret;
732 ret = ngd_xferandwait_ack(ctrl, &txn);
733 if (ret)
734 return ret;
735 }
736 txn.len = 0;
737 list_for_each_entry(pch, &sb->mark_removal, pending) {
738 struct slim_ich *slc;
739 slc = &ctrl->chans[pch->chan];
740 if (!slc) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530741 SLIM_WARN(dev, "no channel in removal?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600742 return -ENXIO;
743 }
744 if (txn.len == 0) {
Sagar Dhariab47c8962012-10-30 13:44:08 -0600745 /* Per protocol, only last 5 bits for client no. */
Sagar Dharia71fcea52012-09-12 23:21:57 -0600746 wbuf[txn.len++] = (u8) (SLIM_CH_REMOVE << 6) |
Sagar Dhariab47c8962012-10-30 13:44:08 -0600747 (sb->laddr & 0x1f);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600748 ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
749 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530750 SLIM_WARN(dev, "no tid for channel define?\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600751 return -ENXIO;
752 }
753 }
754 wbuf[txn.len++] = slc->chan;
Kiran Gundab27683f2014-01-07 15:58:31 +0530755 SLIM_INFO(dev, "slim remove chan:%d, laddr: 0x%x\n",
756 slc->chan, sb->laddr);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600757 }
758 if (txn.len) {
759 txn.mc = SLIM_USR_MC_CHAN_CTRL;
760 txn.rl = txn.len + 4;
761 ret = ngd_xferandwait_ack(ctrl, &txn);
Sagar Dharia21f88552014-02-07 00:10:37 -0700762 /* HW restarting, channel removal should succeed */
763 if (ret == -EREMOTEIO)
764 return 0;
765 else if (ret)
Sagar Dharia71fcea52012-09-12 23:21:57 -0600766 return ret;
767
768 txn.mc = SLIM_USR_MC_RECONFIG_NOW;
769 txn.len = 2;
770 wbuf[1] = sb->laddr;
771 txn.rl = txn.len + 4;
772 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
773 if (ret)
774 return ret;
775 ret = ngd_xferandwait_ack(ctrl, &txn);
776 if (ret)
777 return ret;
778 txn.len = 0;
779 }
Sagar Dharia24419e32013-01-14 17:56:32 -0700780 return 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600781}
782
783static int ngd_set_laddr(struct slim_controller *ctrl, const u8 *ea,
784 u8 elen, u8 laddr)
785{
786 return 0;
787}
788
789static int ngd_get_laddr(struct slim_controller *ctrl, const u8 *ea,
790 u8 elen, u8 *laddr)
791{
792 int ret;
793 u8 wbuf[10];
794 struct slim_msg_txn txn;
795 DECLARE_COMPLETION_ONSTACK(done);
796 txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
797 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
798 txn.la = SLIM_LA_MGR;
799 txn.ec = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600800 ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
801 if (ret) {
Sagar Dharia71fcea52012-09-12 23:21:57 -0600802 return ret;
803 }
804 memcpy(&wbuf[1], ea, elen);
805 txn.mc = SLIM_USR_MC_ADDR_QUERY;
806 txn.rl = 11;
807 txn.len = 7;
808 txn.wbuf = wbuf;
809 txn.rbuf = NULL;
810 ret = ngd_xferandwait_ack(ctrl, &txn);
811 if (!ret && txn.la == 0xFF)
812 ret = -ENXIO;
813 else if (!ret)
814 *laddr = txn.la;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600815 return ret;
816}
817
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600818static void ngd_slim_setup_msg_path(struct msm_slim_ctrl *dev)
Sagar Dharia24419e32013-01-14 17:56:32 -0700819{
Sagar Dharia24419e32013-01-14 17:56:32 -0700820 if (dev->state == MSM_CTRL_DOWN) {
821 msm_slim_sps_init(dev, dev->bam_mem,
822 NGD_BASE(dev->ctrl.nr,
823 dev->ver) + NGD_STATUS, true);
824 } else {
825 if (dev->use_rx_msgqs == MSM_MSGQ_DISABLED)
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600826 goto setup_tx_msg_path;
827 msm_slim_connect_endp(dev, &dev->rx_msgq,
Sagar Dharia24419e32013-01-14 17:56:32 -0700828 &dev->rx_msgq_notify);
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600829
830setup_tx_msg_path:
831 if (dev->use_tx_msgqs == MSM_MSGQ_DISABLED)
832 return;
833 msm_slim_connect_endp(dev, &dev->tx_msgq,
834 NULL);
Sagar Dharia24419e32013-01-14 17:56:32 -0700835 }
836}
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600837
Sagar Dharia71fcea52012-09-12 23:21:57 -0600838static void ngd_slim_rx(struct msm_slim_ctrl *dev, u8 *buf)
839{
840 u8 mc, mt, len;
841 int ret;
842 u32 msgq_en = 1;
843
844 len = buf[0] & 0x1F;
845 mt = (buf[0] >> 5) & 0x7;
846 mc = buf[1];
847 if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
848 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
849 struct slim_msg_txn txn;
Sagar Dharia0a693332013-04-15 17:59:03 -0600850 int retries = 0;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600851 u8 wbuf[8];
852 txn.dt = SLIM_MSG_DEST_LOGICALADDR;
853 txn.ec = 0;
854 txn.rbuf = NULL;
855 txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
856 txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
857 txn.la = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600858 wbuf[0] = SAT_MAGIC_LSB;
859 wbuf[1] = SAT_MAGIC_MSB;
860 wbuf[2] = SAT_MSG_VER;
861 wbuf[3] = SAT_MSG_PROT;
862 txn.wbuf = wbuf;
863 txn.len = 4;
Kiran Gundab27683f2014-01-07 15:58:31 +0530864 SLIM_INFO(dev, "SLIM SAT: Rcvd master capability\n");
Sagar Dharia24419e32013-01-14 17:56:32 -0700865 if (dev->state >= MSM_CTRL_ASLEEP) {
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600866 ngd_slim_setup_msg_path(dev);
Sagar Dharia24419e32013-01-14 17:56:32 -0700867 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
Sagar Dharia33beca02012-10-22 16:21:46 -0600868 msgq_en |= NGD_CFG_RX_MSGQ_EN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -0600869 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
870 msgq_en |= NGD_CFG_TX_MSGQ_EN;
Sagar Dharia33beca02012-10-22 16:21:46 -0600871 writel_relaxed(msgq_en, dev->base +
872 NGD_BASE(dev->ctrl.nr, dev->ver));
873 /* make sure NGD MSG-Q config goes through */
874 mb();
875 }
Sagar Dharia0a693332013-04-15 17:59:03 -0600876capability_retry:
877 txn.rl = 8;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600878 ret = ngd_xfer_msg(&dev->ctrl, &txn);
879 if (!ret) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600880 enum msm_ctrl_state prev_state = dev->state;
Kiran Gundab27683f2014-01-07 15:58:31 +0530881 SLIM_INFO(dev,
882 "SLIM SAT: capability exchange successful\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -0600883 dev->state = MSM_CTRL_AWAKE;
Sagar Dharia33beca02012-10-22 16:21:46 -0600884 if (prev_state >= MSM_CTRL_ASLEEP)
885 complete(&dev->reconf);
886 else
Kiran Gundab27683f2014-01-07 15:58:31 +0530887 SLIM_ERR(dev,
888 "SLIM: unexpected capability, state:%d\n",
889 prev_state);
Sagar Dharia33beca02012-10-22 16:21:46 -0600890 /* ADSP SSR, send device_up notifications */
891 if (prev_state == MSM_CTRL_DOWN)
Sagar Dhariae44cc822014-02-07 21:32:34 -0700892 complete(&dev->qmi.slave_notify);
Sagar Dharia0a693332013-04-15 17:59:03 -0600893 } else if (ret == -EIO) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530894 SLIM_WARN(dev, "capability message NACKed, retrying\n");
Sagar Dharia0a693332013-04-15 17:59:03 -0600895 if (retries < INIT_MX_RETRIES) {
896 msleep(DEF_RETRY_MS);
897 retries++;
898 goto capability_retry;
899 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600900 }
901 }
902 if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
903 mc == SLIM_MSG_MC_REPLY_VALUE) {
904 u8 tid = buf[3];
905 dev_dbg(dev->dev, "tid:%d, len:%d\n", tid, len);
906 slim_msg_response(&dev->ctrl, &buf[4], tid,
907 len - 4);
908 pm_runtime_mark_last_busy(dev->dev);
909 }
910 if (mc == SLIM_USR_MC_ADDR_REPLY &&
911 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700912 struct slim_msg_txn *txn;
Sagar Dharia71fcea52012-09-12 23:21:57 -0600913 u8 failed_ea[6] = {0, 0, 0, 0, 0, 0};
Sagar Dhariad2959352012-12-01 15:43:01 -0700914 mutex_lock(&dev->ctrl.m_ctrl);
915 txn = dev->ctrl.txnt[buf[3]];
916 if (!txn) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530917 SLIM_WARN(dev,
918 "LADDR response after timeout, tid:0x%x\n",
919 buf[3]);
Sagar Dhariad2959352012-12-01 15:43:01 -0700920 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600921 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700922 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600923 if (memcmp(&buf[4], failed_ea, 6))
924 txn->la = buf[10];
925 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700926 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600927 complete(txn->comp);
928 }
929 if (mc == SLIM_USR_MC_GENERIC_ACK &&
930 mt == SLIM_MSG_MT_SRC_REFERRED_USER) {
Sagar Dhariad2959352012-12-01 15:43:01 -0700931 struct slim_msg_txn *txn;
932 mutex_lock(&dev->ctrl.m_ctrl);
933 txn = dev->ctrl.txnt[buf[3]];
934 if (!txn) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530935 SLIM_WARN(dev, "ACK received after timeout, tid:0x%x\n",
Sagar Dhariad2959352012-12-01 15:43:01 -0700936 buf[3]);
937 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600938 return;
Sagar Dhariad2959352012-12-01 15:43:01 -0700939 }
Sagar Dharia71fcea52012-09-12 23:21:57 -0600940 dev_dbg(dev->dev, "got response:tid:%d, response:0x%x",
941 (int)buf[3], buf[4]);
942 if (!(buf[4] & MSM_SAT_SUCCSS)) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530943 SLIM_WARN(dev, "TID:%d, NACK code:0x%x\n", (int)buf[3],
Sagar Dharia71fcea52012-09-12 23:21:57 -0600944 buf[4]);
945 txn->ec = -EIO;
946 }
947 dev->ctrl.txnt[buf[3]] = NULL;
Sagar Dhariad2959352012-12-01 15:43:01 -0700948 mutex_unlock(&dev->ctrl.m_ctrl);
Sagar Dharia71fcea52012-09-12 23:21:57 -0600949 complete(txn->comp);
950 }
951}
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700952
Sagar Dhariab94aa312014-01-14 17:36:32 -0700953static int ngd_slim_power_up(struct msm_slim_ctrl *dev, bool mdm_restart)
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700954{
Sagar Dharia33beca02012-10-22 16:21:46 -0600955 void __iomem *ngd;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600956 int timeout, ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -0600957 enum msm_ctrl_state cur_state = dev->state;
958 u32 laddr;
Sagar Dharia24419e32013-01-14 17:56:32 -0700959 u32 ngd_int = (NGD_INT_TX_NACKED_2 |
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700960 NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
961 NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
962 NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
Sagar Dharia33beca02012-10-22 16:21:46 -0600963
Sagar Dhariab94aa312014-01-14 17:36:32 -0700964 if (!mdm_restart && cur_state == MSM_CTRL_DOWN) {
Sagar Dharia33beca02012-10-22 16:21:46 -0600965 int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
966 HZ);
967 if (!timeout)
Kiran Gundab27683f2014-01-07 15:58:31 +0530968 SLIM_ERR(dev, "slimbus QMI init timed out\n");
Sagar Dharia33beca02012-10-22 16:21:46 -0600969 }
970
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600971 /* No need to vote if contorller is not in low power mode */
Sagar Dhariab94aa312014-01-14 17:36:32 -0700972 if (!mdm_restart &&
973 (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP)) {
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600974 ret = msm_slim_qmi_power_request(dev, true);
975 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530976 SLIM_ERR(dev, "SLIM QMI power request failed:%d\n",
977 ret);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600978 return ret;
979 }
Sagar Dharia33beca02012-10-22 16:21:46 -0600980 }
981 if (!dev->ver) {
982 dev->ver = readl_relaxed(dev->base);
983 /* Version info in 16 MSbits */
984 dev->ver >>= 16;
985 }
986 ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
987 laddr = readl_relaxed(ngd + NGD_STATUS);
988 if (laddr & NGD_LADDR) {
Sagar Dhariacc1001e2012-11-06 13:56:42 -0700989 /*
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600990 * external MDM restart case where ADSP itself was active framer
991 * For example, modem restarted when playback was active
992 */
993 if (cur_state == MSM_CTRL_AWAKE) {
Kiran Gundab27683f2014-01-07 15:58:31 +0530994 SLIM_INFO(dev, "Subsys restart: ADSP active framer\n");
Naveen Kaje0ba80fa2013-10-29 18:24:15 -0600995 return 0;
996 }
997 /*
Sagar Dharia33beca02012-10-22 16:21:46 -0600998 * ADSP power collapse case, where HW wasn't reset.
999 * Reconnect BAM pipes if disconnected
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001000 */
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001001 ngd_slim_setup_msg_path(dev);
Sagar Dharia33beca02012-10-22 16:21:46 -06001002 return 0;
Sagar Dhariab94aa312014-01-14 17:36:32 -07001003 }
1004
1005 if (mdm_restart) {
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001006 /*
Sagar Dhariab94aa312014-01-14 17:36:32 -07001007 * external MDM SSR when MDM is active framer
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001008 * ADSP will reset slimbus HW. disconnect BAM pipes so that
1009 * they can be connected after capability message is received.
1010 * Set device state to ASLEEP to be synchronous with the HW
1011 */
Sagar Dhariab94aa312014-01-14 17:36:32 -07001012 /* make current state as DOWN */
1013 cur_state = MSM_CTRL_DOWN;
Kiran Gundab27683f2014-01-07 15:58:31 +05301014 SLIM_INFO(dev,
1015 "SLIM MDM restart: MDM active framer: reinit HW\n");
Sagar Dhariab94aa312014-01-14 17:36:32 -07001016 /* disconnect BAM pipes */
1017 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
1018 dev->use_rx_msgqs = MSM_MSGQ_DOWN;
1019 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
1020 dev->use_tx_msgqs = MSM_MSGQ_DOWN;
1021 dev->state = MSM_CTRL_DOWN;
Sagar Dharia33beca02012-10-22 16:21:46 -06001022 }
Sagar Dhariab94aa312014-01-14 17:36:32 -07001023 /* SSR scenario, need to disconnect pipe before connecting */
Sagar Dhariada48bd62013-03-21 18:02:40 -06001024 if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
1025 struct msm_slim_endp *endpoint = &dev->rx_msgq;
1026 sps_disconnect(endpoint->sps);
1027 sps_free_endpoint(endpoint->sps);
1028 dev->use_rx_msgqs = MSM_MSGQ_RESET;
1029 }
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001030 if (dev->use_tx_msgqs == MSM_MSGQ_DOWN) {
1031 struct msm_slim_endp *endpoint = &dev->tx_msgq;
1032 sps_disconnect(endpoint->sps);
1033 sps_free_endpoint(endpoint->sps);
1034 dev->use_tx_msgqs = MSM_MSGQ_RESET;
1035 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001036 /*
1037 * ADSP power collapse case (OR SSR), where HW was reset
1038 * BAM programming will happen when capability message is received
1039 */
1040 writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001041 NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -06001042 /*
1043 * Enable NGD. Configure NGD in register acc. mode until master
1044 * announcement is received
1045 */
Sagar Dharia24419e32013-01-14 17:56:32 -07001046 writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
Sagar Dharia33beca02012-10-22 16:21:46 -06001047 /* make sure NGD enabling goes through */
1048 mb();
1049
1050 timeout = wait_for_completion_timeout(&dev->reconf, HZ);
1051 if (!timeout) {
Kiran Gundab27683f2014-01-07 15:58:31 +05301052 SLIM_ERR(dev, "Failed to receive master capability\n");
Sagar Dharia33beca02012-10-22 16:21:46 -06001053 return -ETIMEDOUT;
1054 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301055 if (cur_state == MSM_CTRL_DOWN) {
Sagar Dharia33beca02012-10-22 16:21:46 -06001056 complete(&dev->ctrl_up);
Kiran Gundab27683f2014-01-07 15:58:31 +05301057 /* Resetting the log level */
1058 SLIM_RST_LOGLVL(dev);
1059 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001060 return 0;
1061}
1062
1063static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
1064{
1065 int ret = 0;
1066 if (enable) {
1067 ret = msm_slim_qmi_init(dev, false);
1068 /* controller state should be in sync with framework state */
1069 if (!ret) {
Sagar Dharia33beca02012-10-22 16:21:46 -06001070 complete(&dev->qmi.qmi_comp);
Sagar Dharia33beca02012-10-22 16:21:46 -06001071 if (!pm_runtime_enabled(dev->dev) ||
1072 !pm_runtime_suspended(dev->dev))
1073 ngd_slim_runtime_resume(dev->dev);
1074 else
1075 pm_runtime_resume(dev->dev);
1076 pm_runtime_mark_last_busy(dev->dev);
1077 pm_runtime_put(dev->dev);
1078 } else
Kiran Gundab27683f2014-01-07 15:58:31 +05301079 SLIM_ERR(dev, "qmi init fail, ret:%d, state:%d\n",
Sagar Dharia33beca02012-10-22 16:21:46 -06001080 ret, dev->state);
1081 } else {
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001082 msm_slim_qmi_exit(dev);
1083 }
1084
Sagar Dharia33beca02012-10-22 16:21:46 -06001085 return ret;
1086}
1087
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001088static int ngd_slim_power_down(struct msm_slim_ctrl *dev)
Sagar Dharia33beca02012-10-22 16:21:46 -06001089{
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001090 int i;
1091 struct slim_controller *ctrl = &dev->ctrl;
1092 mutex_lock(&ctrl->m_ctrl);
1093 /* Pending response for a message */
1094 for (i = 0; i < ctrl->last_tid; i++) {
1095 if (ctrl->txnt[i]) {
1096 SLIM_INFO(dev, "NGD down:txn-rsp for %d pending", i);
1097 mutex_unlock(&ctrl->m_ctrl);
1098 return -EBUSY;
1099 }
1100 }
1101 mutex_unlock(&ctrl->m_ctrl);
1102 msm_slim_disconnect_endp(dev, &dev->rx_msgq,
1103 &dev->use_rx_msgqs);
1104 msm_slim_disconnect_endp(dev, &dev->tx_msgq,
1105 &dev->use_tx_msgqs);
1106 return msm_slim_qmi_power_request(dev, false);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001107}
1108
Sagar Dharia71fcea52012-09-12 23:21:57 -06001109static int ngd_slim_rx_msgq_thread(void *data)
1110{
1111 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
1112 struct completion *notify = &dev->rx_msgq_notify;
1113 int ret = 0, index = 0;
1114 u32 mc = 0;
1115 u32 mt = 0;
1116 u32 buffer[10];
1117 u8 msg_len = 0;
1118
1119 while (!kthread_should_stop()) {
1120 set_current_state(TASK_INTERRUPTIBLE);
Kiran Gundabbb3e312014-03-17 16:11:40 +05301121 wait_for_completion(notify);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001122 /* 1 irq notification per message */
Sagar Dharia24419e32013-01-14 17:56:32 -07001123 if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001124 msm_slim_rx_dequeue(dev, (u8 *)buffer);
1125 ngd_slim_rx(dev, (u8 *)buffer);
1126 continue;
1127 }
1128 ret = msm_slim_rx_msgq_get(dev, buffer, index);
1129 if (ret) {
Kiran Gundab27683f2014-01-07 15:58:31 +05301130 SLIM_ERR(dev, "rx_msgq_get() failed 0x%x\n", ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001131 continue;
1132 }
1133
1134 /* Wait for complete message */
1135 if (index++ == 0) {
1136 msg_len = *buffer & 0x1F;
1137 mt = (buffer[0] >> 5) & 0x7;
1138 mc = (buffer[0] >> 8) & 0xff;
1139 dev_dbg(dev->dev, "MC: %x, MT: %x\n", mc, mt);
1140 }
1141 if ((index * 4) >= msg_len) {
1142 index = 0;
1143 ngd_slim_rx(dev, (u8 *)buffer);
1144 } else
1145 continue;
1146 }
1147 return 0;
1148}
1149
Sagar Dhariae44cc822014-02-07 21:32:34 -07001150static int ngd_notify_slaves(void *data)
Sagar Dharia33beca02012-10-22 16:21:46 -06001151{
Sagar Dhariae44cc822014-02-07 21:32:34 -07001152 struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
Sagar Dharia33beca02012-10-22 16:21:46 -06001153 struct slim_controller *ctrl = &dev->ctrl;
1154 struct slim_device *sbdev;
Sagar Dharia21f88552014-02-07 00:10:37 -07001155 struct list_head *pos, *next;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001156 int ret, i = 0;
1157 while (!kthread_should_stop()) {
1158 set_current_state(TASK_INTERRUPTIBLE);
Kiran Gundabbb3e312014-03-17 16:11:40 +05301159 wait_for_completion(&dev->qmi.slave_notify);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001160 /* Probe devices for first notification */
1161 if (!i) {
Kiran Gunda2b457b02014-04-04 14:58:56 +05301162 i++;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001163 dev->err = 0;
1164 if (dev->dev->of_node)
1165 of_register_slim_devices(&dev->ctrl);
1166
1167 /*
1168 * Add devices registered with board-info now that
1169 * controller is up
1170 */
1171 slim_ctrl_add_boarddevs(&dev->ctrl);
1172 } else {
1173 slim_framer_booted(ctrl);
1174 }
Sagar Dharia33beca02012-10-22 16:21:46 -06001175 mutex_lock(&ctrl->m_ctrl);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001176 list_for_each_safe(pos, next, &ctrl->devs) {
Kiran Gunda2b457b02014-04-04 14:58:56 +05301177 int j;
Sagar Dhariae44cc822014-02-07 21:32:34 -07001178 sbdev = list_entry(pos, struct slim_device, dev_list);
1179 mutex_unlock(&ctrl->m_ctrl);
Kiran Gunda2b457b02014-04-04 14:58:56 +05301180 for (j = 0; j < LADDR_RETRY; j++) {
Sagar Dhariae44cc822014-02-07 21:32:34 -07001181 ret = slim_get_logical_addr(sbdev,
1182 sbdev->e_addr,
1183 6, &sbdev->laddr);
1184 if (!ret)
1185 break;
1186 else /* time for ADSP to assign LA */
1187 msleep(20);
1188 }
1189 mutex_lock(&ctrl->m_ctrl);
1190 }
1191 mutex_unlock(&ctrl->m_ctrl);
Sagar Dharia33beca02012-10-22 16:21:46 -06001192 }
Sagar Dhariae44cc822014-02-07 21:32:34 -07001193 return 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001194}
1195
1196static void ngd_adsp_down(struct work_struct *work)
1197{
1198 struct msm_slim_qmi *qmi =
1199 container_of(work, struct msm_slim_qmi, ssr_down);
1200 struct msm_slim_ctrl *dev =
1201 container_of(qmi, struct msm_slim_ctrl, qmi);
1202 struct slim_controller *ctrl = &dev->ctrl;
1203 struct slim_device *sbdev;
Sagar Dharia33beca02012-10-22 16:21:46 -06001204
1205 ngd_slim_enable(dev, false);
1206 /* disconnect BAM pipes */
Sagar Dhariada48bd62013-03-21 18:02:40 -06001207 if (dev->use_rx_msgqs == MSM_MSGQ_ENABLED)
1208 dev->use_rx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001209 if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
1210 dev->use_tx_msgqs = MSM_MSGQ_DOWN;
Sagar Dharia33beca02012-10-22 16:21:46 -06001211 msm_slim_sps_exit(dev, false);
Sagar Dharia33beca02012-10-22 16:21:46 -06001212 /* device up should be called again after SSR */
1213 list_for_each_entry(sbdev, &ctrl->devs, dev_list)
Sagar Dhariaf68d71f2013-07-31 17:43:46 -06001214 slim_report_absent(sbdev);
Kiran Gundab27683f2014-01-07 15:58:31 +05301215 SLIM_INFO(dev, "SLIM ADSP SSR (DOWN) done\n");
Sagar Dharia33beca02012-10-22 16:21:46 -06001216}
1217
1218static void ngd_adsp_up(struct work_struct *work)
1219{
1220 struct msm_slim_qmi *qmi =
1221 container_of(work, struct msm_slim_qmi, ssr_up);
1222 struct msm_slim_ctrl *dev =
1223 container_of(qmi, struct msm_slim_ctrl, qmi);
1224 ngd_slim_enable(dev, true);
1225}
1226
Kiran Gundab27683f2014-01-07 15:58:31 +05301227static ssize_t show_mask(struct device *device, struct device_attribute *attr,
1228 char *buf)
1229{
1230 struct platform_device *pdev = to_platform_device(device);
1231 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1232 return snprintf(buf, sizeof(int), "%u\n", dev->ipc_log_mask);
1233}
1234
1235static ssize_t set_mask(struct device *device, struct device_attribute *attr,
1236 const char *buf, size_t count)
1237{
1238 struct platform_device *pdev = to_platform_device(device);
1239 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1240
1241 dev->ipc_log_mask = buf[0] - '0';
1242 if (dev->ipc_log_mask > DBG_LEV)
1243 dev->ipc_log_mask = DBG_LEV;
1244 return count;
1245}
1246
1247static DEVICE_ATTR(debug_mask, S_IRUGO | S_IWUSR, show_mask, set_mask);
1248
Sagar Dharia71fcea52012-09-12 23:21:57 -06001249static int __devinit ngd_slim_probe(struct platform_device *pdev)
1250{
1251 struct msm_slim_ctrl *dev;
1252 int ret;
1253 struct resource *bam_mem;
1254 struct resource *slim_mem;
1255 struct resource *irq, *bam_irq;
Sagar Dharia24419e32013-01-14 17:56:32 -07001256 bool rxreg_access = false;
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001257 bool slim_mdm = false;
Naveen Kaje284da552014-03-26 09:54:29 -06001258 const char *ext_modem_id = NULL;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001259
Sagar Dharia71fcea52012-09-12 23:21:57 -06001260 slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1261 "slimbus_physical");
1262 if (!slim_mem) {
1263 dev_err(&pdev->dev, "no slimbus physical memory resource\n");
1264 return -ENODEV;
1265 }
1266 bam_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1267 "slimbus_bam_physical");
1268 if (!bam_mem) {
1269 dev_err(&pdev->dev, "no slimbus BAM memory resource\n");
1270 return -ENODEV;
1271 }
1272 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1273 "slimbus_irq");
1274 if (!irq) {
1275 dev_err(&pdev->dev, "no slimbus IRQ resource\n");
1276 return -ENODEV;
1277 }
1278 bam_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1279 "slimbus_bam_irq");
1280 if (!bam_irq) {
1281 dev_err(&pdev->dev, "no slimbus BAM IRQ resource\n");
1282 return -ENODEV;
1283 }
1284
1285 dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
Kiran Gunda318cac42013-10-21 17:00:15 +05301286 if (IS_ERR_OR_NULL(dev)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001287 dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
1288 return PTR_ERR(dev);
1289 }
1290 dev->dev = &pdev->dev;
1291 platform_set_drvdata(pdev, dev);
1292 slim_set_ctrldata(&dev->ctrl, dev);
Kiran Gundab27683f2014-01-07 15:58:31 +05301293
1294 /* Create IPC log context */
1295 dev->ipc_slimbus_log = ipc_log_context_create(IPC_SLIMBUS_LOG_PAGES,
1296 dev_name(dev->dev));
1297 if (!dev->ipc_slimbus_log)
1298 dev_err(&pdev->dev, "error creating ipc_logging context\n");
1299 else {
1300 /* Initialize the log mask */
1301 dev->ipc_log_mask = INFO_LEV;
1302 dev->default_ipc_log_mask = INFO_LEV;
1303 SLIM_INFO(dev, "start logging for slim dev %s\n",
1304 dev_name(dev->dev));
1305 }
1306 ret = sysfs_create_file(&dev->dev->kobj, &dev_attr_debug_mask.attr);
1307 if (ret) {
1308 dev_err(&pdev->dev, "Failed to create dev. attr\n");
1309 dev->sysfs_created = false;
1310 } else
1311 dev->sysfs_created = true;
1312
Sagar Dharia71fcea52012-09-12 23:21:57 -06001313 dev->base = ioremap(slim_mem->start, resource_size(slim_mem));
1314 if (!dev->base) {
1315 dev_err(&pdev->dev, "IOremap failed\n");
1316 ret = -ENOMEM;
1317 goto err_ioremap_failed;
1318 }
1319 dev->bam.base = ioremap(bam_mem->start, resource_size(bam_mem));
1320 if (!dev->bam.base) {
1321 dev_err(&pdev->dev, "BAM IOremap failed\n");
1322 ret = -ENOMEM;
1323 goto err_ioremap_bam_failed;
1324 }
1325 if (pdev->dev.of_node) {
1326
1327 ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
1328 &dev->ctrl.nr);
1329 if (ret) {
1330 dev_err(&pdev->dev, "Cell index not specified:%d", ret);
1331 goto err_ctrl_failed;
1332 }
Sagar Dharia24419e32013-01-14 17:56:32 -07001333 rxreg_access = of_property_read_bool(pdev->dev.of_node,
1334 "qcom,rxreg-access");
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001335 of_property_read_u32(pdev->dev.of_node, "qcom,apps-ch-pipes",
1336 &dev->pdata.apps_pipes);
1337 of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
1338 &dev->pdata.eapc);
Naveen Kaje284da552014-03-26 09:54:29 -06001339 ret = of_property_read_string(pdev->dev.of_node,
1340 "qcom,slim-mdm", &ext_modem_id);
1341 if (!ret)
1342 slim_mdm = true;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001343 } else {
1344 dev->ctrl.nr = pdev->id;
1345 }
Sagar Dhariaa3c6a382013-06-21 12:18:20 -06001346 /*
1347 * Keep PGD's logical address as manager's. Query it when first data
1348 * channel request comes in
1349 */
1350 dev->pgdla = SLIM_LA_MGR;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001351 dev->ctrl.nchans = MSM_SLIM_NCHANS;
1352 dev->ctrl.nports = MSM_SLIM_NPORTS;
1353 dev->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
1354 dev->framer.superfreq =
1355 dev->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
1356 dev->ctrl.a_framer = &dev->framer;
1357 dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
1358 dev->ctrl.set_laddr = ngd_set_laddr;
1359 dev->ctrl.get_laddr = ngd_get_laddr;
1360 dev->ctrl.allocbw = ngd_allocbw;
1361 dev->ctrl.xfer_msg = ngd_xfer_msg;
Sagar Dhariab046b3c2014-01-27 21:30:48 -07001362 dev->ctrl.xfer_user_msg = ngd_user_msg;
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001363 dev->ctrl.wakeup = NULL;
Sagar Dharia100e7212013-05-17 18:20:57 -06001364 dev->ctrl.alloc_port = msm_alloc_port;
1365 dev->ctrl.dealloc_port = msm_dealloc_port;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001366 dev->ctrl.port_xfer = msm_slim_port_xfer;
1367 dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001368 dev->bam_mem = bam_mem;
1369
1370 init_completion(&dev->reconf);
Sagar Dharia33beca02012-10-22 16:21:46 -06001371 init_completion(&dev->ctrl_up);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001372 mutex_init(&dev->tx_lock);
1373 spin_lock_init(&dev->rx_lock);
1374 dev->ee = 1;
1375 dev->irq = irq->start;
1376 dev->bam.irq = bam_irq->start;
1377
Sagar Dharia24419e32013-01-14 17:56:32 -07001378 if (rxreg_access)
1379 dev->use_rx_msgqs = MSM_MSGQ_DISABLED;
1380 else
1381 dev->use_rx_msgqs = MSM_MSGQ_RESET;
Sagar Dharia5c8ad192013-05-31 11:39:05 -06001382
1383 /* Enable TX message queues by default as recommended by HW */
1384 dev->use_tx_msgqs = MSM_MSGQ_RESET;
1385
Sagar Dharia71fcea52012-09-12 23:21:57 -06001386 init_completion(&dev->rx_msgq_notify);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001387 init_completion(&dev->qmi.slave_notify);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001388
1389 /* Register with framework */
1390 ret = slim_add_numbered_controller(&dev->ctrl);
1391 if (ret) {
1392 dev_err(dev->dev, "error adding controller\n");
1393 goto err_ctrl_failed;
1394 }
1395
1396 dev->ctrl.dev.parent = &pdev->dev;
1397 dev->ctrl.dev.of_node = pdev->dev.of_node;
Sagar Dharia33beca02012-10-22 16:21:46 -06001398 dev->state = MSM_CTRL_DOWN;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001399
1400 ret = request_irq(dev->irq, ngd_slim_interrupt,
1401 IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
1402
1403 if (ret) {
1404 dev_err(&pdev->dev, "request IRQ failed\n");
1405 goto err_request_irq_failed;
1406 }
1407
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001408 init_completion(&dev->qmi.qmi_comp);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001409 dev->err = -EPROBE_DEFER;
Sagar Dharia33beca02012-10-22 16:21:46 -06001410 pm_runtime_use_autosuspend(dev->dev);
1411 pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
1412 pm_runtime_set_suspended(dev->dev);
1413 pm_runtime_enable(dev->dev);
1414
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001415 if (slim_mdm) {
1416 dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
Naveen Kaje284da552014-03-26 09:54:29 -06001417 dev->mdm.ssr = subsys_notif_register_notifier(ext_modem_id,
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001418 &dev->mdm.nb);
1419 if (IS_ERR_OR_NULL(dev->mdm.ssr))
1420 dev_err(dev->dev,
1421 "subsys_notif_register_notifier failed %p",
1422 dev->mdm.ssr);
1423 }
1424
Sagar Dharia33beca02012-10-22 16:21:46 -06001425 INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
1426 INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001427 dev->qmi.nb.notifier_call = ngd_qmi_available;
Sagar Dharia33beca02012-10-22 16:21:46 -06001428 pm_runtime_get_noresume(dev->dev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001429 ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001430 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001431 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1432 if (ret) {
1433 pr_err("Slimbus QMI service registration failed:%d", ret);
1434 goto qmi_register_failed;
1435 }
1436
Sagar Dharia33beca02012-10-22 16:21:46 -06001437
Sagar Dharia71fcea52012-09-12 23:21:57 -06001438 /* Fire up the Rx message queue thread */
1439 dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
Sagar Dhariae44cc822014-02-07 21:32:34 -07001440 "ngd_rx_thread%d", dev->ctrl.nr);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001441 if (IS_ERR(dev->rx_msgq_thread)) {
1442 ret = PTR_ERR(dev->rx_msgq_thread);
Sagar Dhariae44cc822014-02-07 21:32:34 -07001443 dev_err(dev->dev, "Failed to start Rx thread:%d\n", ret);
1444 goto err_rx_thread_create_failed;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001445 }
1446
Sagar Dhariae44cc822014-02-07 21:32:34 -07001447 /* Start thread to probe, and notify slaves */
1448 dev->qmi.slave_thread = kthread_run(ngd_notify_slaves, dev,
1449 "ngd_notify_sl%d", dev->ctrl.nr);
1450 if (IS_ERR(dev->qmi.slave_thread)) {
1451 ret = PTR_ERR(dev->qmi.slave_thread);
1452 dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
1453 goto err_notify_thread_create_failed;
1454 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301455 SLIM_INFO(dev, "NGD SB controller is up!\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001456 return 0;
1457
Sagar Dhariae44cc822014-02-07 21:32:34 -07001458err_notify_thread_create_failed:
1459 kthread_stop(dev->rx_msgq_thread);
1460err_rx_thread_create_failed:
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001461 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001462 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001463 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
1464qmi_register_failed:
Sagar Dharia71fcea52012-09-12 23:21:57 -06001465 free_irq(dev->irq, dev);
1466err_request_irq_failed:
1467 slim_del_controller(&dev->ctrl);
1468err_ctrl_failed:
1469 iounmap(dev->bam.base);
1470err_ioremap_bam_failed:
1471 iounmap(dev->base);
1472err_ioremap_failed:
Kiran Gundab27683f2014-01-07 15:58:31 +05301473 if (dev->sysfs_created)
1474 sysfs_remove_file(&dev->dev->kobj,
1475 &dev_attr_debug_mask.attr);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001476 kfree(dev);
1477 return ret;
1478}
1479
1480static int __devexit ngd_slim_remove(struct platform_device *pdev)
1481{
1482 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001483 ngd_slim_enable(dev, false);
Kiran Gundab27683f2014-01-07 15:58:31 +05301484 if (dev->sysfs_created)
1485 sysfs_remove_file(&dev->dev->kobj,
1486 &dev_attr_debug_mask.attr);
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001487 qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
Karthikeyan Ramasubramaniane6e24952013-09-20 15:45:18 -06001488 SLIMBUS_QMI_SVC_V1,
Sagar Dhariacc1001e2012-11-06 13:56:42 -07001489 SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001490 pm_runtime_disable(&pdev->dev);
Naveen Kaje0ba80fa2013-10-29 18:24:15 -06001491 if (!IS_ERR_OR_NULL(dev->mdm.ssr))
1492 subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001493 free_irq(dev->irq, dev);
1494 slim_del_controller(&dev->ctrl);
1495 kthread_stop(dev->rx_msgq_thread);
1496 iounmap(dev->bam.base);
1497 iounmap(dev->base);
1498 kfree(dev);
1499 return 0;
1500}
1501
1502#ifdef CONFIG_PM_RUNTIME
1503static int ngd_slim_runtime_idle(struct device *device)
1504{
Sagar Dhariad1468b72013-07-16 12:56:22 -06001505 struct platform_device *pdev = to_platform_device(device);
1506 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1507 if (dev->state == MSM_CTRL_AWAKE)
1508 dev->state = MSM_CTRL_IDLE;
Sagar Dharia71fcea52012-09-12 23:21:57 -06001509 dev_dbg(device, "pm_runtime: idle...\n");
1510 pm_request_autosuspend(device);
1511 return -EAGAIN;
1512}
1513#endif
1514
1515/*
1516 * If PM_RUNTIME is not defined, these 2 functions become helper
1517 * functions to be called from system suspend/resume. So they are not
1518 * inside ifdef CONFIG_PM_RUNTIME
1519 */
Sagar Dharia71fcea52012-09-12 23:21:57 -06001520static int ngd_slim_runtime_resume(struct device *device)
1521{
1522 struct platform_device *pdev = to_platform_device(device);
1523 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1524 int ret = 0;
Sagar Dharia33beca02012-10-22 16:21:46 -06001525 if (dev->state >= MSM_CTRL_ASLEEP)
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001526 ret = ngd_slim_power_up(dev, false);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001527 if (ret) {
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001528 /* Did SSR cause this power up failure */
Sagar Dharia129c7d82013-08-08 19:35:50 -06001529 if (dev->state != MSM_CTRL_DOWN)
1530 dev->state = MSM_CTRL_ASLEEP;
1531 else
Kiran Gundab27683f2014-01-07 15:58:31 +05301532 SLIM_WARN(dev, "HW wakeup attempt during SSR\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001533 } else {
1534 dev->state = MSM_CTRL_AWAKE;
1535 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301536 SLIM_INFO(dev, "Slim runtime resume: ret %d\n", ret);
Sagar Dharia71fcea52012-09-12 23:21:57 -06001537 return ret;
1538}
1539
Sagar Dharia33beca02012-10-22 16:21:46 -06001540#ifdef CONFIG_PM_SLEEP
1541static int ngd_slim_runtime_suspend(struct device *device)
1542{
1543 struct platform_device *pdev = to_platform_device(device);
1544 struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
1545 int ret = 0;
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001546 ret = ngd_slim_power_down(dev);
Sagar Dharia33beca02012-10-22 16:21:46 -06001547 if (ret) {
1548 if (ret != -EBUSY)
Sagar Dharia9bd4c712014-04-30 18:36:17 -06001549 SLIM_INFO(dev, "slim resource not idle:%d\n", ret);
Sagar Dharia33beca02012-10-22 16:21:46 -06001550 dev->state = MSM_CTRL_AWAKE;
1551 } else {
1552 dev->state = MSM_CTRL_ASLEEP;
1553 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301554 SLIM_INFO(dev, "Slim runtime suspend: ret %d\n", ret);
Sagar Dharia33beca02012-10-22 16:21:46 -06001555 return ret;
1556}
1557
Sagar Dharia71fcea52012-09-12 23:21:57 -06001558static int ngd_slim_suspend(struct device *dev)
1559{
1560 int ret = -EBUSY;
Sagar Dhariad1468b72013-07-16 12:56:22 -06001561 struct platform_device *pdev = to_platform_device(dev);
1562 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
1563 if (!pm_runtime_enabled(dev) ||
1564 (!pm_runtime_suspended(dev) &&
1565 cdev->state == MSM_CTRL_IDLE)) {
Sagar Dharia71fcea52012-09-12 23:21:57 -06001566 ret = ngd_slim_runtime_suspend(dev);
Sagar Dhariaa1398282013-01-22 13:26:20 -07001567 /*
1568 * If runtime-PM still thinks it's active, then make sure its
1569 * status is in sync with HW status.
1570 * Since this suspend calls QMI api, it results in holding a
1571 * wakelock. That results in failure of first suspend.
1572 * Subsequent suspend should not call low-power transition
1573 * again since the HW is already in suspended state.
1574 */
1575 if (!ret) {
1576 pm_runtime_disable(dev);
1577 pm_runtime_set_suspended(dev);
1578 pm_runtime_enable(dev);
1579 }
Sagar Dharia71fcea52012-09-12 23:21:57 -06001580 }
1581 if (ret == -EBUSY) {
1582 /*
1583 * There is a possibility that some audio stream is active
1584 * during suspend. We dont want to return suspend failure in
1585 * that case so that display and relevant components can still
1586 * go to suspend.
1587 * If there is some other error, then it should be passed-on
1588 * to system level suspend
1589 */
1590 ret = 0;
1591 }
Kiran Gundab27683f2014-01-07 15:58:31 +05301592 SLIM_INFO(cdev, "system suspend\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001593 return ret;
1594}
1595
1596static int ngd_slim_resume(struct device *dev)
1597{
Kiran Gundab27683f2014-01-07 15:58:31 +05301598 struct platform_device *pdev = to_platform_device(dev);
1599 struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
Sagar Dhariaa1398282013-01-22 13:26:20 -07001600 /*
1601 * Rely on runtime-PM to call resume in case it is enabled.
1602 * Even if it's not enabled, rely on 1st client transaction to do
1603 * clock/power on
1604 */
Kiran Gundab27683f2014-01-07 15:58:31 +05301605 SLIM_INFO(cdev, "system resume\n");
Sagar Dharia71fcea52012-09-12 23:21:57 -06001606 return 0;
1607}
1608#endif /* CONFIG_PM_SLEEP */
1609
1610static const struct dev_pm_ops ngd_slim_dev_pm_ops = {
1611 SET_SYSTEM_SLEEP_PM_OPS(
1612 ngd_slim_suspend,
1613 ngd_slim_resume
1614 )
1615 SET_RUNTIME_PM_OPS(
1616 ngd_slim_runtime_suspend,
1617 ngd_slim_runtime_resume,
1618 ngd_slim_runtime_idle
1619 )
1620};
1621
1622static struct of_device_id ngd_slim_dt_match[] = {
1623 {
1624 .compatible = "qcom,slim-ngd",
1625 },
1626 {}
1627};
1628
1629static struct platform_driver ngd_slim_driver = {
1630 .probe = ngd_slim_probe,
1631 .remove = ngd_slim_remove,
1632 .driver = {
1633 .name = NGD_SLIM_NAME,
1634 .owner = THIS_MODULE,
1635 .pm = &ngd_slim_dev_pm_ops,
1636 .of_match_table = ngd_slim_dt_match,
1637 },
1638};
1639
1640static int ngd_slim_init(void)
1641{
1642 return platform_driver_register(&ngd_slim_driver);
1643}
1644late_initcall(ngd_slim_init);
1645
1646static void ngd_slim_exit(void)
1647{
1648 platform_driver_unregister(&ngd_slim_driver);
1649}
1650module_exit(ngd_slim_exit);
1651
1652MODULE_LICENSE("GPL v2");
1653MODULE_DESCRIPTION("MSM Slimbus controller");
1654MODULE_ALIAS("platform:msm-slim-ngd");