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	u8 __iomem *regs = dev->priv;
 34
 35	*val = readb(regs + (page << 8) + reg);
 36
 37	return 0;
 38}
 39
 40static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 41{
 42	u8 __iomem *regs = dev->priv;
 43
 44	if (WARN_ON(reg % 2))
 45		return -EINVAL;
 46
 47	if (dev->pdata && dev->pdata->big_endian)
 48		*val = ioread16be(regs + (page << 8) + reg);
 49	else
 50		*val = readw(regs + (page << 8) + reg);
 51
 52	return 0;
 53}
 54
 55static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 56{
 57	u8 __iomem *regs = dev->priv;
 58
 59	if (WARN_ON(reg % 4))
 60		return -EINVAL;
 61
 62	if (dev->pdata && dev->pdata->big_endian)
 63		*val = ioread32be(regs + (page << 8) + reg);
 64	else
 65		*val = readl(regs + (page << 8) + reg);
 66
 67	return 0;
 68}
 69
 70static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 71{
 72	u8 __iomem *regs = dev->priv;
 73
 74	if (WARN_ON(reg % 2))
 75		return -EINVAL;
 76
 77	if (reg % 4) {
 78		u16 lo;
 79		u32 hi;
 80
 81		if (dev->pdata && dev->pdata->big_endian) {
 82			lo = ioread16be(regs + (page << 8) + reg);
 83			hi = ioread32be(regs + (page << 8) + reg + 2);
 84		} else {
 85			lo = readw(regs + (page << 8) + reg);
 86			hi = readl(regs + (page << 8) + reg + 2);
 87		}
 88
 89		*val = ((u64)hi << 16) | lo;
 90	} else {
 91		u32 lo;
 92		u16 hi;
 93
 94		if (dev->pdata && dev->pdata->big_endian) {
 95			lo = ioread32be(regs + (page << 8) + reg);
 96			hi = ioread16be(regs + (page << 8) + reg + 4);
 97		} else {
 98			lo = readl(regs + (page << 8) + reg);
 99			hi = readw(regs + (page << 8) + reg + 4);
100		}
101
102		*val = ((u64)hi << 32) | lo;
103	}
104
105	return 0;
106}
107
108static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
109{
110	u8 __iomem *regs = dev->priv;
111	u32 hi, lo;
112
113	if (WARN_ON(reg % 4))
114		return -EINVAL;
115
116	if (dev->pdata && dev->pdata->big_endian) {
117		lo = ioread32be(regs + (page << 8) + reg);
118		hi = ioread32be(regs + (page << 8) + reg + 4);
119	} else {
120		lo = readl(regs + (page << 8) + reg);
121		hi = readl(regs + (page << 8) + reg + 4);
122	}
123
124	*val = ((u64)hi << 32) | lo;
125
126	return 0;
127}
128
129static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
130{
131	u8 __iomem *regs = dev->priv;
132
133	writeb(value, regs + (page << 8) + reg);
134
135	return 0;
136}
137
138static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
139			    u16 value)
140{
141	u8 __iomem *regs = dev->priv;
142
143	if (WARN_ON(reg % 2))
144		return -EINVAL;
145
146	if (dev->pdata && dev->pdata->big_endian)
147		iowrite16be(value, regs + (page << 8) + reg);
148	else
149		writew(value, regs + (page << 8) + reg);
150
151	return 0;
152}
153
154static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
155			    u32 value)
156{
157	u8 __iomem *regs = dev->priv;
158
159	if (WARN_ON(reg % 4))
160		return -EINVAL;
161
162	if (dev->pdata && dev->pdata->big_endian)
163		iowrite32be(value, regs + (page << 8) + reg);
164	else
165		writel(value, regs + (page << 8) + reg);
166
167	return 0;
168}
169
170static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
171			    u64 value)
172{
173	if (WARN_ON(reg % 2))
174		return -EINVAL;
175
176	if (reg % 4) {
177		u32 hi = (u32)(value >> 16);
178		u16 lo = (u16)value;
179
180		b53_mmap_write16(dev, page, reg, lo);
181		b53_mmap_write32(dev, page, reg + 2, hi);
182	} else {
183		u16 hi = (u16)(value >> 32);
184		u32 lo = (u32)value;
185
186		b53_mmap_write32(dev, page, reg, lo);
187		b53_mmap_write16(dev, page, reg + 4, hi);
188	}
189
190	return 0;
191}
192
193static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
194			    u64 value)
195{
196	u32 hi, lo;
197
198	hi = upper_32_bits(value);
199	lo = lower_32_bits(value);
200
201	if (WARN_ON(reg % 4))
202		return -EINVAL;
203
204	b53_mmap_write32(dev, page, reg, lo);
205	b53_mmap_write32(dev, page, reg + 4, hi);
206
207	return 0;
208}
209
210static const struct b53_io_ops b53_mmap_ops = {
211	.read8 = b53_mmap_read8,
212	.read16 = b53_mmap_read16,
213	.read32 = b53_mmap_read32,
214	.read48 = b53_mmap_read48,
215	.read64 = b53_mmap_read64,
216	.write8 = b53_mmap_write8,
217	.write16 = b53_mmap_write16,
218	.write32 = b53_mmap_write32,
219	.write48 = b53_mmap_write48,
220	.write64 = b53_mmap_write64,
221};
222
223static int b53_mmap_probe(struct platform_device *pdev)
224{
225	struct b53_platform_data *pdata = pdev->dev.platform_data;
226	struct b53_device *dev;
227
228	if (!pdata)
229		return -EINVAL;
230
231	dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
232	if (!dev)
233		return -ENOMEM;
234
235	dev->pdata = pdata;
236
237	platform_set_drvdata(pdev, dev);
238
239	return b53_switch_register(dev);
240}
241
242static int b53_mmap_remove(struct platform_device *pdev)
243{
244	struct b53_device *dev = platform_get_drvdata(pdev);
245
246	if (dev)
247		b53_switch_remove(dev);
248
249	return 0;
250}
251
252static const struct of_device_id b53_mmap_of_table[] = {
253	{ .compatible = "brcm,bcm3384-switch" },
254	{ .compatible = "brcm,bcm6328-switch" },
255	{ .compatible = "brcm,bcm6368-switch" },
256	{ .compatible = "brcm,bcm63xx-switch" },
257	{ /* sentinel */ },
258};
259MODULE_DEVICE_TABLE(of, b53_mmap_of_table);
260
261static struct platform_driver b53_mmap_driver = {
262	.probe = b53_mmap_probe,
263	.remove = b53_mmap_remove,
264	.driver = {
265		.name = "b53-switch",
266		.of_match_table = b53_mmap_of_table,
267	},
268};
269
270module_platform_driver(b53_mmap_driver);
271MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
272MODULE_DESCRIPTION("B53 MMAP access driver");
273MODULE_LICENSE("Dual BSD/GPL");