[PATCH 05/10] ARM: bcm2835: Add the mailbox power channel driver.

Eric Anholt
2015-03-02T20:54:39Z

This just enables the power to the USB controller, so that DWC2 can
initialize.

The downstream tree has an interface to this channel for tracking
enables from multiple clients, except it doesn't have any clients as
far as I can see. For now, just make the simplest thing that gets USB
working.

Signed-off-by: Eric Anholt <eric-WhKQ6XTQaPysTnJN9+BGXg@public.gmane.org>
---
drivers/mailbox/Makefile | 1 +
drivers/mailbox/bcm2835-mailbox-power.c | 127 ++++++++++++++++++++++++++++++++
2 files changed, 128 insertions(+)
create mode 100644 drivers/mailbox/bcm2835-mailbox-power.c

diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 7feb8da..619d815 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PCC) += pcc.o
obj-$(CONFIG_ALTERA_MBOX) += mailbox-altera.o

obj-$(CONFIG_BCM2835_MBOX) += bcm2835-mailbox.o
+obj-$(CONFIG_BCM2835_MBOX) += bcm2835-mailbox-power.o
diff --git a/drivers/mailbox/bcm2835-mailbox-power.c b/drivers/mailbox/bcm2835-mailbox-power.c
new file mode 100644
index 0000000..f09c855
--- /dev/null
+++ b/drivers/mailbox/bcm2835-mailbox-power.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2015 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Defines a module for accessing the power channel of the
+ * BCM2835 mailbox.
+ *
+ * For now, we just turn on the USB power so that DWC2 can initialize.
+ * At a later time we may extend this into a driver that actually does
+ * runtime power management on the other channels.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define BCM_POWER_USB (1 << 3)
+#define BCM_MBOX_DATA_SHIFT 4
+
+struct bcm_mbox_power {
+ struct device *dev;
+ struct mbox_client cl;
+ struct mbox_chan *chan;
+ struct completion c;
+ uint32_t response;
+};
+
+struct bcm_mbox_power *mbox_power;
+
+static void response_callback(struct mbox_client *cl, void *mssg)
+{
+ mbox_power->response = (uint32_t)mssg;
+ complete(&mbox_power->c);
+}
+
+/*
+ * Submits a set of concatenated tags to the VPU firmware through the
+ * mailbox power interface.
+ *
+ * The buffer header and the ending tag are added by this function and
+ * don't need to be supplied, just the actual tags for your operation.
+ * See struct bcm_mbox_power_tag_header for the per-tag structure.
+ */
+static int bcm_mbox_set_power(uint32_t power_enables)
+{
+ int ret;
+
+ reinit_completion(&mbox_power->c);
+ ret = mbox_send_message(mbox_power->chan,
+ (void *)(power_enables << BCM_MBOX_DATA_SHIFT));
+ if (ret >= 0)
+ wait_for_completion(&mbox_power->c);
+
+ return ret;
+}
+
+static int bcm2835_mbox_power_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret = 0;
+
+ mbox_power = devm_kzalloc(dev, sizeof(*mbox_power),
+ GFP_KERNEL);
+ if (!mbox_power) {
+ dev_err(dev, "Failed to allocate device memory\n");
+ return -ENOMEM;
+ }
+
+ mbox_power->cl.dev = dev;
+ mbox_power->cl.rx_callback = response_callback;
+ mbox_power->cl.tx_block = true;
+
+ mbox_power->chan = mbox_request_channel(&mbox_power->cl, 0);
+ if (!mbox_power->chan) {
+ dev_err(dev, "Failed to get mbox channel\n");
+ return -ENODEV;
+ }
+
+ init_completion(&mbox_power->c);
+
+ platform_set_drvdata(pdev, mbox_power);
+ mbox_power->dev = dev;
+
+ /* Enable power to the USB phy. */
+ if (IS_ENABLED(CONFIG_USB_DWC2)) {
+ bcm_mbox_set_power(BCM_POWER_USB);
+ bcm2835_mbox_power_initialized = true;
+ }
+
+ return ret;
+}
+
+static int bcm2835_mbox_power_remove(struct platform_device *pdev)
+{
+ bcm_mbox_set_power(0);
+
+ mbox_free_channel(mbox_power->chan);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_mbox_power_of_match[] = {
+ { .compatible = "brcm,bcm2835-mbox-power", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_mbox_power_of_match);
+
+static struct platform_driver bcm2835_mbox_power_driver = {
+ .driver = {
+ .name = "bcm2835-mbox-power",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_mbox_power_of_match,
+ },
+ .probe = bcm2835_mbox_power_probe,
+ .remove = bcm2835_mbox_power_remove,
+};
+module_platform_driver(bcm2835_mbox_power_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric-WhKQ6XTQaPysTnJN9+BGXg@public.gmane.org>");
+MODULE_DESCRIPTION("BCM2835 mailbox power channel");
+MODULE_LICENSE("GPL v2");
--
2.1.4