Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2016 BayLibre SAS.
  4 * Author: Neil Armstrong <narmstrong@baylibre.com>
  5 * Synchronised with arm_mhu.c from :
  6 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
  7 * Copyright (C) 2015 Linaro Ltd.
  8 * Author: Jassi Brar <jaswinder.singh@linaro.org>
 
 
 
 
 
 
 
 
 
  9 */
 10
 11#include <linux/interrupt.h>
 12#include <linux/spinlock.h>
 13#include <linux/mutex.h>
 14#include <linux/delay.h>
 15#include <linux/slab.h>
 16#include <linux/err.h>
 17#include <linux/io.h>
 18#include <linux/mod_devicetable.h>
 19#include <linux/module.h>
 20#include <linux/platform_device.h>
 21#include <linux/mailbox_controller.h>
 22
 23#define INTR_SET_OFS	0x0
 24#define INTR_STAT_OFS	0x4
 25#define INTR_CLR_OFS	0x8
 26
 27#define MHU_SEC_OFFSET	0x0
 28#define MHU_LP_OFFSET	0xc
 29#define MHU_HP_OFFSET	0x18
 30#define TX_REG_OFFSET	0x24
 31
 32#define MHU_CHANS	3
 33
 34struct platform_mhu_link {
 35	int irq;
 36	void __iomem *tx_reg;
 37	void __iomem *rx_reg;
 38};
 39
 40struct platform_mhu {
 41	void __iomem *base;
 42	struct platform_mhu_link mlink[MHU_CHANS];
 43	struct mbox_chan chan[MHU_CHANS];
 44	struct mbox_controller mbox;
 45};
 46
 47static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)
 48{
 49	struct mbox_chan *chan = p;
 50	struct platform_mhu_link *mlink = chan->con_priv;
 51	u32 val;
 52
 53	val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
 54	if (!val)
 55		return IRQ_NONE;
 56
 57	mbox_chan_received_data(chan, (void *)&val);
 58
 59	writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
 60
 61	return IRQ_HANDLED;
 62}
 63
 64static bool platform_mhu_last_tx_done(struct mbox_chan *chan)
 65{
 66	struct platform_mhu_link *mlink = chan->con_priv;
 67	u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
 68
 69	return (val == 0);
 70}
 71
 72static int platform_mhu_send_data(struct mbox_chan *chan, void *data)
 73{
 74	struct platform_mhu_link *mlink = chan->con_priv;
 75	u32 *arg = data;
 76
 77	writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
 78
 79	return 0;
 80}
 81
 82static int platform_mhu_startup(struct mbox_chan *chan)
 83{
 84	struct platform_mhu_link *mlink = chan->con_priv;
 85	u32 val;
 86	int ret;
 87
 88	val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
 89	writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
 90
 91	ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,
 92			  IRQF_SHARED, "platform_mhu_link", chan);
 93	if (ret) {
 94		dev_err(chan->mbox->dev,
 95			"Unable to acquire IRQ %d\n", mlink->irq);
 96		return ret;
 97	}
 98
 99	return 0;
100}
101
102static void platform_mhu_shutdown(struct mbox_chan *chan)
103{
104	struct platform_mhu_link *mlink = chan->con_priv;
105
106	free_irq(mlink->irq, chan);
107}
108
109static const struct mbox_chan_ops platform_mhu_ops = {
110	.send_data = platform_mhu_send_data,
111	.startup = platform_mhu_startup,
112	.shutdown = platform_mhu_shutdown,
113	.last_tx_done = platform_mhu_last_tx_done,
114};
115
116static int platform_mhu_probe(struct platform_device *pdev)
117{
118	int i, err;
119	struct platform_mhu *mhu;
120	struct device *dev = &pdev->dev;
 
121	int platform_mhu_reg[MHU_CHANS] = {
122		MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET
123	};
124
125	/* Allocate memory for device */
126	mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
127	if (!mhu)
128		return -ENOMEM;
129
130	mhu->base = devm_platform_ioremap_resource(pdev, 0);
 
131	if (IS_ERR(mhu->base)) {
132		dev_err(dev, "ioremap failed\n");
133		return PTR_ERR(mhu->base);
134	}
135
136	for (i = 0; i < MHU_CHANS; i++) {
137		mhu->chan[i].con_priv = &mhu->mlink[i];
138		mhu->mlink[i].irq = platform_get_irq(pdev, i);
139		if (mhu->mlink[i].irq < 0)
 
140			return mhu->mlink[i].irq;
 
141		mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];
142		mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
143	}
144
145	mhu->mbox.dev = dev;
146	mhu->mbox.chans = &mhu->chan[0];
147	mhu->mbox.num_chans = MHU_CHANS;
148	mhu->mbox.ops = &platform_mhu_ops;
149	mhu->mbox.txdone_irq = false;
150	mhu->mbox.txdone_poll = true;
151	mhu->mbox.txpoll_period = 1;
152
153	platform_set_drvdata(pdev, mhu);
154
155	err = devm_mbox_controller_register(dev, &mhu->mbox);
156	if (err) {
157		dev_err(dev, "Failed to register mailboxes %d\n", err);
158		return err;
159	}
160
161	dev_info(dev, "Platform MHU Mailbox registered\n");
162	return 0;
163}
164
 
 
 
 
 
 
 
 
 
165static const struct of_device_id platform_mhu_dt_ids[] = {
166	{ .compatible = "amlogic,meson-gxbb-mhu", },
167	{ /* sentinel */ },
168};
169MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);
170
171static struct platform_driver platform_mhu_driver = {
172	.probe	= platform_mhu_probe,
 
173	.driver = {
174		.name = "platform-mhu",
175		.of_match_table	= platform_mhu_dt_ids,
176	},
177};
178
179module_platform_driver(platform_mhu_driver);
180
181MODULE_LICENSE("GPL v2");
182MODULE_ALIAS("platform:platform-mhu");
183MODULE_DESCRIPTION("Platform MHU Driver");
184MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
v4.17
 
  1/*
  2 * Copyright (C) 2016 BayLibre SAS.
  3 * Author: Neil Armstrong <narmstrong@baylibre.com>
  4 * Synchronised with arm_mhu.c from :
  5 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
  6 * Copyright (C) 2015 Linaro Ltd.
  7 * Author: Jassi Brar <jaswinder.singh@linaro.org>
  8 *
  9 * This program is free software: you can redistribute it and/or modify
 10 * it under the terms of the GNU General Public License as published by
 11 * the Free Software Foundation, version 2 of the License.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 */
 18
 19#include <linux/interrupt.h>
 20#include <linux/spinlock.h>
 21#include <linux/mutex.h>
 22#include <linux/delay.h>
 23#include <linux/slab.h>
 24#include <linux/err.h>
 25#include <linux/io.h>
 
 26#include <linux/module.h>
 27#include <linux/platform_device.h>
 28#include <linux/mailbox_controller.h>
 29
 30#define INTR_SET_OFS	0x0
 31#define INTR_STAT_OFS	0x4
 32#define INTR_CLR_OFS	0x8
 33
 34#define MHU_SEC_OFFSET	0x0
 35#define MHU_LP_OFFSET	0xc
 36#define MHU_HP_OFFSET	0x18
 37#define TX_REG_OFFSET	0x24
 38
 39#define MHU_CHANS	3
 40
 41struct platform_mhu_link {
 42	int irq;
 43	void __iomem *tx_reg;
 44	void __iomem *rx_reg;
 45};
 46
 47struct platform_mhu {
 48	void __iomem *base;
 49	struct platform_mhu_link mlink[MHU_CHANS];
 50	struct mbox_chan chan[MHU_CHANS];
 51	struct mbox_controller mbox;
 52};
 53
 54static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)
 55{
 56	struct mbox_chan *chan = p;
 57	struct platform_mhu_link *mlink = chan->con_priv;
 58	u32 val;
 59
 60	val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
 61	if (!val)
 62		return IRQ_NONE;
 63
 64	mbox_chan_received_data(chan, (void *)&val);
 65
 66	writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
 67
 68	return IRQ_HANDLED;
 69}
 70
 71static bool platform_mhu_last_tx_done(struct mbox_chan *chan)
 72{
 73	struct platform_mhu_link *mlink = chan->con_priv;
 74	u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
 75
 76	return (val == 0);
 77}
 78
 79static int platform_mhu_send_data(struct mbox_chan *chan, void *data)
 80{
 81	struct platform_mhu_link *mlink = chan->con_priv;
 82	u32 *arg = data;
 83
 84	writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
 85
 86	return 0;
 87}
 88
 89static int platform_mhu_startup(struct mbox_chan *chan)
 90{
 91	struct platform_mhu_link *mlink = chan->con_priv;
 92	u32 val;
 93	int ret;
 94
 95	val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
 96	writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
 97
 98	ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,
 99			  IRQF_SHARED, "platform_mhu_link", chan);
100	if (ret) {
101		dev_err(chan->mbox->dev,
102			"Unable to acquire IRQ %d\n", mlink->irq);
103		return ret;
104	}
105
106	return 0;
107}
108
109static void platform_mhu_shutdown(struct mbox_chan *chan)
110{
111	struct platform_mhu_link *mlink = chan->con_priv;
112
113	free_irq(mlink->irq, chan);
114}
115
116static const struct mbox_chan_ops platform_mhu_ops = {
117	.send_data = platform_mhu_send_data,
118	.startup = platform_mhu_startup,
119	.shutdown = platform_mhu_shutdown,
120	.last_tx_done = platform_mhu_last_tx_done,
121};
122
123static int platform_mhu_probe(struct platform_device *pdev)
124{
125	int i, err;
126	struct platform_mhu *mhu;
127	struct device *dev = &pdev->dev;
128	struct resource *res;
129	int platform_mhu_reg[MHU_CHANS] = {
130		MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET
131	};
132
133	/* Allocate memory for device */
134	mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
135	if (!mhu)
136		return -ENOMEM;
137
138	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
139	mhu->base = devm_ioremap_resource(dev, res);
140	if (IS_ERR(mhu->base)) {
141		dev_err(dev, "ioremap failed\n");
142		return PTR_ERR(mhu->base);
143	}
144
145	for (i = 0; i < MHU_CHANS; i++) {
146		mhu->chan[i].con_priv = &mhu->mlink[i];
147		mhu->mlink[i].irq = platform_get_irq(pdev, i);
148		if (mhu->mlink[i].irq < 0) {
149			dev_err(dev, "failed to get irq%d\n", i);
150			return mhu->mlink[i].irq;
151		}
152		mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];
153		mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
154	}
155
156	mhu->mbox.dev = dev;
157	mhu->mbox.chans = &mhu->chan[0];
158	mhu->mbox.num_chans = MHU_CHANS;
159	mhu->mbox.ops = &platform_mhu_ops;
160	mhu->mbox.txdone_irq = false;
161	mhu->mbox.txdone_poll = true;
162	mhu->mbox.txpoll_period = 1;
163
164	platform_set_drvdata(pdev, mhu);
165
166	err = mbox_controller_register(&mhu->mbox);
167	if (err) {
168		dev_err(dev, "Failed to register mailboxes %d\n", err);
169		return err;
170	}
171
172	dev_info(dev, "Platform MHU Mailbox registered\n");
173	return 0;
174}
175
176static int platform_mhu_remove(struct platform_device *pdev)
177{
178	struct platform_mhu *mhu = platform_get_drvdata(pdev);
179
180	mbox_controller_unregister(&mhu->mbox);
181
182	return 0;
183}
184
185static const struct of_device_id platform_mhu_dt_ids[] = {
186	{ .compatible = "amlogic,meson-gxbb-mhu", },
187	{ /* sentinel */ },
188};
189MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);
190
191static struct platform_driver platform_mhu_driver = {
192	.probe	= platform_mhu_probe,
193	.remove	= platform_mhu_remove,
194	.driver = {
195		.name = "platform-mhu",
196		.of_match_table	= platform_mhu_dt_ids,
197	},
198};
199
200module_platform_driver(platform_mhu_driver);
201
202MODULE_LICENSE("GPL v2");
203MODULE_ALIAS("platform:platform-mhu");
204MODULE_DESCRIPTION("Platform MHU Driver");
205MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");