Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 * B53 register access through memory mapped registers
  3 *
  4 * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
  5 *
  6 * Permission to use, copy, modify, and/or distribute this software for any
  7 * purpose with or without fee is hereby granted, provided that the above
  8 * copyright notice and this permission notice appear in all copies.
  9 *
 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 17 */
 18
 19#include <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/io.h>
 22#include <linux/platform_device.h>
 23#include <linux/platform_data/b53.h>
 24
 25#include "b53_priv.h"
 26
 27struct b53_mmap_priv {
 28	void __iomem *regs;
 29};
 30
 31static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 32{
 33	struct b53_mmap_priv *priv = dev->priv;
 34	void __iomem *regs = priv->regs;
 35
 36	*val = readb(regs + (page << 8) + reg);
 37
 38	return 0;
 39}
 40
 41static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 42{
 43	struct b53_mmap_priv *priv = dev->priv;
 44	void __iomem *regs = priv->regs;
 45
 46	if (WARN_ON(reg % 2))
 47		return -EINVAL;
 48
 49	if (dev->pdata && dev->pdata->big_endian)
 50		*val = ioread16be(regs + (page << 8) + reg);
 51	else
 52		*val = readw(regs + (page << 8) + reg);
 53
 54	return 0;
 55}
 56
 57static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 58{
 59	struct b53_mmap_priv *priv = dev->priv;
 60	void __iomem *regs = priv->regs;
 61
 62	if (WARN_ON(reg % 4))
 63		return -EINVAL;
 64
 65	if (dev->pdata && dev->pdata->big_endian)
 66		*val = ioread32be(regs + (page << 8) + reg);
 67	else
 68		*val = readl(regs + (page << 8) + reg);
 69
 70	return 0;
 71}
 72
 73static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 74{
 75	struct b53_mmap_priv *priv = dev->priv;
 76	void __iomem *regs = priv->regs;
 77
 78	if (WARN_ON(reg % 2))
 79		return -EINVAL;
 80
 81	if (reg % 4) {
 82		u16 lo;
 83		u32 hi;
 84
 85		if (dev->pdata && dev->pdata->big_endian) {
 86			lo = ioread16be(regs + (page << 8) + reg);
 87			hi = ioread32be(regs + (page << 8) + reg + 2);
 88		} else {
 89			lo = readw(regs + (page << 8) + reg);
 90			hi = readl(regs + (page << 8) + reg + 2);
 91		}
 92
 93		*val = ((u64)hi << 16) | lo;
 94	} else {
 95		u32 lo;
 96		u16 hi;
 97
 98		if (dev->pdata && dev->pdata->big_endian) {
 99			lo = ioread32be(regs + (page << 8) + reg);
100			hi = ioread16be(regs + (page << 8) + reg + 4);
101		} else {
102			lo = readl(regs + (page << 8) + reg);
103			hi = readw(regs + (page << 8) + reg + 4);
104		}
105
106		*val = ((u64)hi << 32) | lo;
107	}
108
109	return 0;
110}
111
112static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
113{
114	struct b53_mmap_priv *priv = dev->priv;
115	void __iomem *regs = priv->regs;
116	u32 hi, lo;
117
118	if (WARN_ON(reg % 4))
119		return -EINVAL;
120
121	if (dev->pdata && dev->pdata->big_endian) {
122		lo = ioread32be(regs + (page << 8) + reg);
123		hi = ioread32be(regs + (page << 8) + reg + 4);
124	} else {
125		lo = readl(regs + (page << 8) + reg);
126		hi = readl(regs + (page << 8) + reg + 4);
127	}
128
129	*val = ((u64)hi << 32) | lo;
130
131	return 0;
132}
133
134static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
135{
136	struct b53_mmap_priv *priv = dev->priv;
137	void __iomem *regs = priv->regs;
138
139	writeb(value, regs + (page << 8) + reg);
140
141	return 0;
142}
143
144static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
145			    u16 value)
146{
147	struct b53_mmap_priv *priv = dev->priv;
148	void __iomem *regs = priv->regs;
149
150	if (WARN_ON(reg % 2))
151		return -EINVAL;
152
153	if (dev->pdata && dev->pdata->big_endian)
154		iowrite16be(value, regs + (page << 8) + reg);
155	else
156		writew(value, regs + (page << 8) + reg);
157
158	return 0;
159}
160
161static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
162			    u32 value)
163{
164	struct b53_mmap_priv *priv = dev->priv;
165	void __iomem *regs = priv->regs;
166
167	if (WARN_ON(reg % 4))
168		return -EINVAL;
169
170	if (dev->pdata && dev->pdata->big_endian)
171		iowrite32be(value, regs + (page << 8) + reg);
172	else
173		writel(value, regs + (page << 8) + reg);
174
175	return 0;
176}
177
178static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
179			    u64 value)
180{
181	if (WARN_ON(reg % 2))
182		return -EINVAL;
183
184	if (reg % 4) {
185		u32 hi = (u32)(value >> 16);
186		u16 lo = (u16)value;
187
188		b53_mmap_write16(dev, page, reg, lo);
189		b53_mmap_write32(dev, page, reg + 2, hi);
190	} else {
191		u16 hi = (u16)(value >> 32);
192		u32 lo = (u32)value;
193
194		b53_mmap_write32(dev, page, reg, lo);
195		b53_mmap_write16(dev, page, reg + 4, hi);
196	}
197
198	return 0;
199}
200
201static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
202			    u64 value)
203{
204	u32 hi, lo;
205
206	hi = upper_32_bits(value);
207	lo = lower_32_bits(value);
208
209	if (WARN_ON(reg % 4))
210		return -EINVAL;
211
212	b53_mmap_write32(dev, page, reg, lo);
213	b53_mmap_write32(dev, page, reg + 4, hi);
214
215	return 0;
216}
217
218static const struct b53_io_ops b53_mmap_ops = {
219	.read8 = b53_mmap_read8,
220	.read16 = b53_mmap_read16,
221	.read32 = b53_mmap_read32,
222	.read48 = b53_mmap_read48,
223	.read64 = b53_mmap_read64,
224	.write8 = b53_mmap_write8,
225	.write16 = b53_mmap_write16,
226	.write32 = b53_mmap_write32,
227	.write48 = b53_mmap_write48,
228	.write64 = b53_mmap_write64,
229};
230
231static int b53_mmap_probe(struct platform_device *pdev)
232{
233	struct b53_platform_data *pdata = pdev->dev.platform_data;
234	struct b53_mmap_priv *priv;
235	struct b53_device *dev;
236
237	if (!pdata)
238		return -EINVAL;
239
240	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
241	if (!priv)
242		return -ENOMEM;
243
244	priv->regs = pdata->regs;
245
246	dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv);
247	if (!dev)
248		return -ENOMEM;
249
250	dev->pdata = pdata;
251
252	platform_set_drvdata(pdev, dev);
253
254	return b53_switch_register(dev);
255}
256
257static int b53_mmap_remove(struct platform_device *pdev)
258{
259	struct b53_device *dev = platform_get_drvdata(pdev);
260
261	if (dev)
262		b53_switch_remove(dev);
263
264	return 0;
265}
266
267static const struct of_device_id b53_mmap_of_table[] = {
268	{ .compatible = "brcm,bcm3384-switch" },
269	{ .compatible = "brcm,bcm6328-switch" },
270	{ .compatible = "brcm,bcm6368-switch" },
271	{ .compatible = "brcm,bcm63xx-switch" },
272	{ /* sentinel */ },
273};
274MODULE_DEVICE_TABLE(of, b53_mmap_of_table);
275
276static struct platform_driver b53_mmap_driver = {
277	.probe = b53_mmap_probe,
278	.remove = b53_mmap_remove,
279	.driver = {
280		.name = "b53-switch",
281		.of_match_table = b53_mmap_of_table,
282	},
283};
284
285module_platform_driver(b53_mmap_driver);
286MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
287MODULE_DESCRIPTION("B53 MMAP access driver");
288MODULE_LICENSE("Dual BSD/GPL");