Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 656 lines 17 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Broadcom BCM74110 Mailbox Driver 4 * 5 * Copyright (c) 2025 Broadcom 6 */ 7#include <linux/list.h> 8#include <linux/types.h> 9#include <linux/workqueue.h> 10#include <linux/io-64-nonatomic-hi-lo.h> 11#include <linux/interrupt.h> 12#include <linux/module.h> 13#include <linux/platform_device.h> 14#include <linux/of.h> 15#include <linux/delay.h> 16#include <linux/mailbox_controller.h> 17#include <linux/bitfield.h> 18#include <linux/slab.h> 19 20#define BCM_MBOX_BASE(sel) ((sel) * 0x40) 21#define BCM_MBOX_IRQ_BASE(sel) (((sel) * 0x20) + 0x800) 22 23#define BCM_MBOX_CFGA 0x0 24#define BCM_MBOX_CFGB 0x4 25#define BCM_MBOX_CFGC 0x8 26#define BCM_MBOX_CFGD 0xc 27#define BCM_MBOX_CTRL 0x10 28#define BCM_MBOX_CTRL_EN BIT(0) 29#define BCM_MBOX_CTRL_CLR BIT(1) 30#define BCM_MBOX_STATUS0 0x14 31#define BCM_MBOX_STATUS0_NOT_EMPTY BIT(28) 32#define BCM_MBOX_STATUS0_FULL BIT(29) 33#define BCM_MBOX_STATUS1 0x18 34#define BCM_MBOX_STATUS2 0x1c 35#define BCM_MBOX_WDATA 0x20 36#define BCM_MBOX_RDATA 0x28 37 38#define BCM_MBOX_IRQ_STATUS 0x0 39#define BCM_MBOX_IRQ_SET 0x4 40#define BCM_MBOX_IRQ_CLEAR 0x8 41#define BCM_MBOX_IRQ_MASK_STATUS 0xc 42#define BCM_MBOX_IRQ_MASK_SET 0x10 43#define BCM_MBOX_IRQ_MASK_CLEAR 0x14 44#define BCM_MBOX_IRQ_TIMEOUT BIT(0) 45#define BCM_MBOX_IRQ_NOT_EMPTY BIT(1) 46#define BCM_MBOX_IRQ_FULL BIT(2) 47#define BCM_MBOX_IRQ_LOW_WM BIT(3) 48#define BCM_MBOX_IRQ_HIGH_WM BIT(4) 49 50#define BCM_LINK_CODE0 0xbe0 51#define BCM_LINK_CODE1 0xbe1 52#define BCM_LINK_CODE2 0xbe2 53 54enum { 55 BCM_MSG_FUNC_LINK_START = 0, 56 BCM_MSG_FUNC_LINK_STOP, 57 BCM_MSG_FUNC_SHMEM_TX, 58 BCM_MSG_FUNC_SHMEM_RX, 59 BCM_MSG_FUNC_SHMEM_STOP, 60 BCM_MSG_FUNC_MAX, 61}; 62 63enum { 64 BCM_MSG_SVC_INIT = 0, 65 BCM_MSG_SVC_PMC, 66 BCM_MSG_SVC_SCMI, 67 BCM_MSG_SVC_DPFE, 68 BCM_MSG_SVC_MAX, 69}; 70 71struct bcm74110_mbox_msg { 72 struct list_head list_entry; 73#define BCM_MSG_VERSION_MASK GENMASK(31, 29) 74#define BCM_MSG_VERSION 0x1 75#define BCM_MSG_REQ_MASK BIT(28) 76#define BCM_MSG_RPLY_MASK BIT(27) 77#define BCM_MSG_SVC_MASK GENMASK(26, 24) 78#define BCM_MSG_FUNC_MASK GENMASK(23, 16) 79#define BCM_MSG_LENGTH_MASK GENMASK(15, 4) 80#define BCM_MSG_SLOT_MASK GENMASK(3, 0) 81 82#define BCM_MSG_SET_FIELD(hdr, field, val) \ 83 do { \ 84 hdr &= ~BCM_MSG_##field##_MASK; \ 85 hdr |= FIELD_PREP(BCM_MSG_##field##_MASK, val); \ 86 } while (0) 87 88#define BCM_MSG_GET_FIELD(hdr, field) \ 89 FIELD_GET(BCM_MSG_##field##_MASK, hdr) 90 u32 msg; 91}; 92 93struct bcm74110_mbox_chan { 94 struct bcm74110_mbox *mbox; 95 bool en; 96 int slot; 97 int type; 98}; 99 100struct bcm74110_mbox { 101 struct platform_device *pdev; 102 void __iomem *base; 103 104 int tx_chan; 105 int rx_chan; 106 int rx_irq; 107 struct list_head rx_svc_init_list; 108 spinlock_t rx_svc_list_lock; 109 110 struct mbox_controller controller; 111 struct bcm74110_mbox_chan *mbox_chan; 112}; 113 114#define BCM74110_OFFSET_IO_WRITEL_MACRO(name, offset_base) \ 115static void bcm74110_##name##_writel(struct bcm74110_mbox *mbox,\ 116 u32 val, u32 off) \ 117{ \ 118 writel_relaxed(val, mbox->base + offset_base + off); \ 119} 120BCM74110_OFFSET_IO_WRITEL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan)); 121BCM74110_OFFSET_IO_WRITEL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan)); 122 123#define BCM74110_OFFSET_IO_READL_MACRO(name, offset_base) \ 124static u32 bcm74110_##name##_readl(struct bcm74110_mbox *mbox, \ 125 u32 off) \ 126{ \ 127 return readl_relaxed(mbox->base + offset_base + off); \ 128} 129BCM74110_OFFSET_IO_READL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan)); 130BCM74110_OFFSET_IO_READL_MACRO(rx, BCM_MBOX_BASE(mbox->rx_chan)); 131BCM74110_OFFSET_IO_READL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan)); 132 133static inline struct bcm74110_mbox *bcm74110_mbox_from_cntrl( 134 struct mbox_controller *cntrl) 135{ 136 return container_of(cntrl, struct bcm74110_mbox, controller); 137} 138 139static void bcm74110_rx_push_init_msg(struct bcm74110_mbox *mbox, u32 val) 140{ 141 struct bcm74110_mbox_msg *msg; 142 143 msg = kzalloc_obj(*msg, GFP_ATOMIC); 144 if (!msg) 145 return; 146 147 INIT_LIST_HEAD(&msg->list_entry); 148 msg->msg = val; 149 150 spin_lock(&mbox->rx_svc_list_lock); 151 list_add_tail(&msg->list_entry, &mbox->rx_svc_init_list); 152 spin_unlock(&mbox->rx_svc_list_lock); 153} 154 155static void bcm74110_rx_process_msg(struct bcm74110_mbox *mbox) 156{ 157 struct device *dev = &mbox->pdev->dev; 158 struct bcm74110_mbox_chan *chan_priv; 159 struct mbox_chan *chan; 160 u32 msg, status; 161 int type; 162 163 do { 164 msg = bcm74110_rx_readl(mbox, BCM_MBOX_RDATA); 165 status = bcm74110_rx_readl(mbox, BCM_MBOX_STATUS0); 166 167 dev_dbg(dev, "rx: [{req=%lu|rply=%lu|srv=%lu|fn=%lu|length=%lu|slot=%lu]\n", 168 BCM_MSG_GET_FIELD(msg, REQ), BCM_MSG_GET_FIELD(msg, RPLY), 169 BCM_MSG_GET_FIELD(msg, SVC), BCM_MSG_GET_FIELD(msg, FUNC), 170 BCM_MSG_GET_FIELD(msg, LENGTH), BCM_MSG_GET_FIELD(msg, SLOT)); 171 172 type = BCM_MSG_GET_FIELD(msg, SVC); 173 switch (type) { 174 case BCM_MSG_SVC_INIT: 175 bcm74110_rx_push_init_msg(mbox, msg); 176 break; 177 case BCM_MSG_SVC_PMC: 178 case BCM_MSG_SVC_SCMI: 179 case BCM_MSG_SVC_DPFE: 180 chan = &mbox->controller.chans[type]; 181 chan_priv = chan->con_priv; 182 if (chan_priv->en) 183 mbox_chan_received_data(chan, NULL); 184 else 185 dev_warn(dev, "Channel not enabled\n"); 186 break; 187 default: 188 dev_warn(dev, "Unsupported msg received\n"); 189 } 190 } while (status & BCM_MBOX_STATUS0_NOT_EMPTY); 191} 192 193static irqreturn_t bcm74110_mbox_isr(int irq, void *data) 194{ 195 struct bcm74110_mbox *mbox = data; 196 u32 status; 197 198 status = bcm74110_irq_readl(mbox, BCM_MBOX_IRQ_STATUS); 199 200 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR); 201 202 if (status & BCM_MBOX_IRQ_NOT_EMPTY) 203 bcm74110_rx_process_msg(mbox); 204 else 205 dev_warn(&mbox->pdev->dev, "Spurious interrupt\n"); 206 207 return IRQ_HANDLED; 208} 209 210static void bcm74110_mbox_mask_and_clear(struct bcm74110_mbox *mbox) 211{ 212 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_MASK_SET); 213 bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR); 214} 215 216static int bcm74110_rx_pop_init_msg(struct bcm74110_mbox *mbox, u32 func_type, 217 u32 *val) 218{ 219 struct bcm74110_mbox_msg *msg, *msg_tmp; 220 unsigned long flags; 221 bool found = false; 222 223 spin_lock_irqsave(&mbox->rx_svc_list_lock, flags); 224 list_for_each_entry_safe(msg, msg_tmp, &mbox->rx_svc_init_list, 225 list_entry) { 226 if (BCM_MSG_GET_FIELD(msg->msg, FUNC) == func_type) { 227 list_del(&msg->list_entry); 228 found = true; 229 break; 230 } 231 } 232 spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags); 233 234 if (!found) 235 return -EINVAL; 236 237 *val = msg->msg; 238 kfree(msg); 239 240 return 0; 241} 242 243static void bcm74110_rx_flush_msg(struct bcm74110_mbox *mbox) 244{ 245 struct bcm74110_mbox_msg *msg, *msg_tmp; 246 LIST_HEAD(list_temp); 247 unsigned long flags; 248 249 spin_lock_irqsave(&mbox->rx_svc_list_lock, flags); 250 list_splice_init(&mbox->rx_svc_init_list, &list_temp); 251 spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags); 252 253 list_for_each_entry_safe(msg, msg_tmp, &list_temp, list_entry) { 254 list_del(&msg->list_entry); 255 kfree(msg); 256 } 257} 258 259#define BCM_DEQUEUE_TIMEOUT_MS 30 260static int bcm74110_rx_pop_init_msg_block(struct bcm74110_mbox *mbox, u32 func_type, 261 u32 *val) 262{ 263 int ret, timeout = 0; 264 265 do { 266 ret = bcm74110_rx_pop_init_msg(mbox, func_type, val); 267 268 if (!ret) 269 return 0; 270 271 /* TODO: Figure out what is a good sleep here. */ 272 usleep_range(1000, 2000); 273 timeout++; 274 } while (timeout < BCM_DEQUEUE_TIMEOUT_MS); 275 276 dev_warn(&mbox->pdev->dev, "Timeout waiting for service init response\n"); 277 return -ETIMEDOUT; 278} 279 280static int bcm74110_mbox_create_msg(int req, int rply, int svc, int func, 281 int length, int slot) 282{ 283 u32 msg = 0; 284 285 BCM_MSG_SET_FIELD(msg, REQ, req); 286 BCM_MSG_SET_FIELD(msg, RPLY, rply); 287 BCM_MSG_SET_FIELD(msg, SVC, svc); 288 BCM_MSG_SET_FIELD(msg, FUNC, func); 289 BCM_MSG_SET_FIELD(msg, LENGTH, length); 290 BCM_MSG_SET_FIELD(msg, SLOT, slot); 291 292 return msg; 293} 294 295static int bcm74110_mbox_tx_msg(struct bcm74110_mbox *mbox, u32 msg) 296{ 297 int val; 298 299 /* We can potentially poll with timeout here instead */ 300 val = bcm74110_tx_readl(mbox, BCM_MBOX_STATUS0); 301 if (val & BCM_MBOX_STATUS0_FULL) { 302 dev_err(&mbox->pdev->dev, "Mailbox full\n"); 303 return -EINVAL; 304 } 305 306 dev_dbg(&mbox->pdev->dev, "tx: [{req=%lu|rply=%lu|srv=%lu|fn=%lu|length=%lu|slot=%lu]\n", 307 BCM_MSG_GET_FIELD(msg, REQ), BCM_MSG_GET_FIELD(msg, RPLY), 308 BCM_MSG_GET_FIELD(msg, SVC), BCM_MSG_GET_FIELD(msg, FUNC), 309 BCM_MSG_GET_FIELD(msg, LENGTH), BCM_MSG_GET_FIELD(msg, SLOT)); 310 311 bcm74110_tx_writel(mbox, msg, BCM_MBOX_WDATA); 312 313 return 0; 314} 315 316#define BCM_MBOX_LINK_TRAINING_RETRIES 5 317static int bcm74110_mbox_link_training(struct bcm74110_mbox *mbox) 318{ 319 int ret, retries = 0; 320 u32 msg = 0, orig_len = 0, len = BCM_LINK_CODE0; 321 322 do { 323 switch (len) { 324 case 0: 325 retries++; 326 dev_warn(&mbox->pdev->dev, 327 "Link train failed, trying again... %d\n", 328 retries); 329 if (retries > BCM_MBOX_LINK_TRAINING_RETRIES) 330 return -EINVAL; 331 len = BCM_LINK_CODE0; 332 fallthrough; 333 case BCM_LINK_CODE0: 334 case BCM_LINK_CODE1: 335 case BCM_LINK_CODE2: 336 msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT, 337 BCM_MSG_FUNC_LINK_START, 338 len, BCM_MSG_SVC_INIT); 339 break; 340 default: 341 break; 342 } 343 344 bcm74110_mbox_tx_msg(mbox, msg); 345 346 /* No response expected for LINK_CODE2 */ 347 if (len == BCM_LINK_CODE2) 348 return 0; 349 350 orig_len = len; 351 352 ret = bcm74110_rx_pop_init_msg_block(mbox, 353 BCM_MSG_GET_FIELD(msg, FUNC), 354 &msg); 355 if (ret) { 356 len = 0; 357 continue; 358 } 359 360 if ((BCM_MSG_GET_FIELD(msg, SVC) != BCM_MSG_SVC_INIT) || 361 (BCM_MSG_GET_FIELD(msg, FUNC) != BCM_MSG_FUNC_LINK_START) || 362 (BCM_MSG_GET_FIELD(msg, SLOT) != 0) || 363 (BCM_MSG_GET_FIELD(msg, RPLY) != 1) || 364 (BCM_MSG_GET_FIELD(msg, REQ) != 0)) { 365 len = 0; 366 continue; 367 } 368 369 len = BCM_MSG_GET_FIELD(msg, LENGTH); 370 371 /* Make sure sequence is good */ 372 if (len != (orig_len + 1)) { 373 len = 0; 374 continue; 375 } 376 } while (1); 377 378 return -EINVAL; 379} 380 381static int bcm74110_mbox_tx_msg_and_wait_ack(struct bcm74110_mbox *mbox, u32 msg) 382{ 383 int ret; 384 u32 recv_msg; 385 386 ret = bcm74110_mbox_tx_msg(mbox, msg); 387 if (ret) 388 return ret; 389 390 ret = bcm74110_rx_pop_init_msg_block(mbox, BCM_MSG_GET_FIELD(msg, FUNC), 391 &recv_msg); 392 if (ret) 393 return ret; 394 395 /* 396 * Modify tx message to verify rx ack. 397 * Flip RPLY/REQ for synchronous messages 398 */ 399 if (BCM_MSG_GET_FIELD(msg, REQ) == 1) { 400 BCM_MSG_SET_FIELD(msg, RPLY, 1); 401 BCM_MSG_SET_FIELD(msg, REQ, 0); 402 } 403 404 if (msg != recv_msg) { 405 dev_err(&mbox->pdev->dev, "Found ack, but ack is invalid\n"); 406 return -EINVAL; 407 } 408 409 return 0; 410} 411 412/* Each index points to 0x100 of HAB MEM. IDX size counts from 0 */ 413#define BCM_MBOX_HAB_MEM_IDX_START 0x30 414#define BCM_MBOX_HAB_MEM_IDX_SIZE 0x0 415static int bcm74110_mbox_shmem_init(struct bcm74110_mbox *mbox) 416{ 417 u32 msg = 0; 418 int ret; 419 420 msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT, 421 BCM_MSG_FUNC_SHMEM_STOP, 422 0, BCM_MSG_SVC_INIT); 423 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); 424 if (ret) 425 return -EINVAL; 426 427 msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT, 428 BCM_MSG_FUNC_SHMEM_TX, 429 BCM_MBOX_HAB_MEM_IDX_START, 430 BCM_MBOX_HAB_MEM_IDX_SIZE); 431 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); 432 if (ret) 433 return -EINVAL; 434 435 msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT, 436 BCM_MSG_FUNC_SHMEM_RX, 437 BCM_MBOX_HAB_MEM_IDX_START, 438 BCM_MBOX_HAB_MEM_IDX_SIZE); 439 ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); 440 if (ret) 441 return -EINVAL; 442 443 return 0; 444} 445 446static int bcm74110_mbox_init(struct bcm74110_mbox *mbox) 447{ 448 int ret = 0; 449 450 /* Disable queues tx/rx */ 451 bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL); 452 453 /* Clear status & restart tx/rx*/ 454 bcm74110_tx_writel(mbox, BCM_MBOX_CTRL_EN | BCM_MBOX_CTRL_CLR, 455 BCM_MBOX_CTRL); 456 457 /* Unmask irq */ 458 bcm74110_irq_writel(mbox, BCM_MBOX_IRQ_NOT_EMPTY, BCM_MBOX_IRQ_MASK_CLEAR); 459 460 ret = bcm74110_mbox_link_training(mbox); 461 if (ret) { 462 dev_err(&mbox->pdev->dev, "Training failed\n"); 463 return ret; 464 } 465 466 return bcm74110_mbox_shmem_init(mbox); 467} 468 469static int bcm74110_mbox_send_data(struct mbox_chan *chan, void *data) 470{ 471 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; 472 u32 msg; 473 474 switch (chan_priv->type) { 475 case BCM_MSG_SVC_PMC: 476 case BCM_MSG_SVC_SCMI: 477 case BCM_MSG_SVC_DPFE: 478 msg = bcm74110_mbox_create_msg(1, 0, chan_priv->type, 0, 479 128 + 28, chan_priv->slot); 480 break; 481 default: 482 return -EINVAL; 483 } 484 485 return bcm74110_mbox_tx_msg(chan_priv->mbox, msg); 486} 487 488static int bcm74110_mbox_chan_startup(struct mbox_chan *chan) 489{ 490 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; 491 492 chan_priv->en = true; 493 494 return 0; 495} 496 497static void bcm74110_mbox_chan_shutdown(struct mbox_chan *chan) 498{ 499 struct bcm74110_mbox_chan *chan_priv = chan->con_priv; 500 501 chan_priv->en = false; 502} 503 504static const struct mbox_chan_ops bcm74110_mbox_chan_ops = { 505 .send_data = bcm74110_mbox_send_data, 506 .startup = bcm74110_mbox_chan_startup, 507 .shutdown = bcm74110_mbox_chan_shutdown, 508}; 509 510static void bcm74110_mbox_shutdown(struct platform_device *pdev) 511{ 512 struct bcm74110_mbox *mbox = dev_get_drvdata(&pdev->dev); 513 u32 msg; 514 515 msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT, 516 BCM_MSG_FUNC_LINK_STOP, 517 0, 0); 518 519 bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg); 520 521 /* Even if we don't receive ACK, lets shut it down */ 522 523 bcm74110_mbox_mask_and_clear(mbox); 524 525 /* Disable queues tx/rx */ 526 bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL); 527 528 /* Flush queues */ 529 bcm74110_rx_flush_msg(mbox); 530} 531 532static struct mbox_chan *bcm74110_mbox_of_xlate(struct mbox_controller *cntrl, 533 const struct of_phandle_args *p) 534{ 535 struct bcm74110_mbox *mbox = bcm74110_mbox_from_cntrl(cntrl); 536 struct device *dev = &mbox->pdev->dev; 537 struct bcm74110_mbox_chan *chan_priv; 538 int slot, type; 539 540 if (p->args_count != 2) { 541 dev_err(dev, "Invalid arguments\n"); 542 return ERR_PTR(-EINVAL); 543 } 544 545 type = p->args[0]; 546 slot = p->args[1]; 547 548 switch (type) { 549 case BCM_MSG_SVC_PMC: 550 case BCM_MSG_SVC_SCMI: 551 case BCM_MSG_SVC_DPFE: 552 if (slot > BCM_MBOX_HAB_MEM_IDX_SIZE) { 553 dev_err(dev, "Not enough shared memory\n"); 554 return ERR_PTR(-EINVAL); 555 } 556 chan_priv = cntrl->chans[type].con_priv; 557 chan_priv->slot = slot; 558 chan_priv->type = type; 559 break; 560 default: 561 dev_err(dev, "Invalid channel type: %d\n", type); 562 return ERR_PTR(-EINVAL); 563 } 564 565 return &cntrl->chans[type]; 566} 567 568static int bcm74110_mbox_probe(struct platform_device *pdev) 569{ 570 struct device *dev = &pdev->dev; 571 struct bcm74110_mbox *mbox; 572 int i, ret; 573 574 mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); 575 if (!mbox) 576 return -ENOMEM; 577 578 mbox->pdev = pdev; 579 platform_set_drvdata(pdev, mbox); 580 581 mbox->base = devm_platform_ioremap_resource(pdev, 0); 582 if (IS_ERR(mbox->base)) 583 return dev_err_probe(dev, PTR_ERR(mbox->base), "Failed to iomap\n"); 584 585 ret = of_property_read_u32(dev->of_node, "brcm,tx", &mbox->tx_chan); 586 if (ret) 587 return dev_err_probe(dev, ret, "Failed to find tx channel\n"); 588 589 ret = of_property_read_u32(dev->of_node, "brcm,rx", &mbox->rx_chan); 590 if (ret) 591 return dev_err_probe(dev, ret, "Failed to find rx channel\n"); 592 593 mbox->rx_irq = platform_get_irq(pdev, 0); 594 if (mbox->rx_irq < 0) 595 return mbox->rx_irq; 596 597 INIT_LIST_HEAD(&mbox->rx_svc_init_list); 598 spin_lock_init(&mbox->rx_svc_list_lock); 599 bcm74110_mbox_mask_and_clear(mbox); 600 601 ret = devm_request_irq(dev, mbox->rx_irq, bcm74110_mbox_isr, 602 IRQF_NO_SUSPEND, pdev->name, mbox); 603 if (ret) 604 return dev_err_probe(dev, ret, "Failed to request irq\n"); 605 606 mbox->controller.ops = &bcm74110_mbox_chan_ops; 607 mbox->controller.dev = dev; 608 mbox->controller.num_chans = BCM_MSG_SVC_MAX; 609 mbox->controller.of_xlate = &bcm74110_mbox_of_xlate; 610 mbox->controller.chans = devm_kcalloc(dev, BCM_MSG_SVC_MAX, 611 sizeof(*mbox->controller.chans), 612 GFP_KERNEL); 613 if (!mbox->controller.chans) 614 return -ENOMEM; 615 616 mbox->mbox_chan = devm_kcalloc(dev, BCM_MSG_SVC_MAX, 617 sizeof(*mbox->mbox_chan), 618 GFP_KERNEL); 619 if (!mbox->mbox_chan) 620 return -ENOMEM; 621 622 for (i = 0; i < BCM_MSG_SVC_MAX; i++) { 623 mbox->mbox_chan[i].mbox = mbox; 624 mbox->controller.chans[i].con_priv = &mbox->mbox_chan[i]; 625 } 626 627 ret = devm_mbox_controller_register(dev, &mbox->controller); 628 if (ret) 629 return ret; 630 631 ret = bcm74110_mbox_init(mbox); 632 if (ret) 633 return ret; 634 635 return 0; 636} 637 638static const struct of_device_id bcm74110_mbox_of_match[] = { 639 { .compatible = "brcm,bcm74110-mbox", }, 640 { /* sentinel */ }, 641}; 642MODULE_DEVICE_TABLE(of, bcm74110_mbox_of_match); 643 644static struct platform_driver bcm74110_mbox_driver = { 645 .driver = { 646 .name = "bcm74110-mbox", 647 .of_match_table = bcm74110_mbox_of_match, 648 }, 649 .probe = bcm74110_mbox_probe, 650 .shutdown = bcm74110_mbox_shutdown, 651}; 652module_platform_driver(bcm74110_mbox_driver); 653 654MODULE_AUTHOR("Justin Chen <justin.chen@broadcom.com>"); 655MODULE_DESCRIPTION("BCM74110 mailbox driver"); 656MODULE_LICENSE("GPL");