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