Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2020 NovaTech LLC
  4 * George McCollister <george.mccollister@gmail.com>
  5 */
  6
  7#include <linux/bitfield.h>
  8#include <linux/bits.h>
  9#include <linux/mdio.h>
 10#include <linux/module.h>
 11#include <linux/phy.h>
 12#include <linux/if_vlan.h>
 13#include <linux/of.h>
 14#include "xrs700x.h"
 15#include "xrs700x_reg.h"
 16
 17#define XRS_MDIO_IBA0	0x10
 18#define XRS_MDIO_IBA1	0x11
 19#define XRS_MDIO_IBD	0x14
 20
 21#define XRS_IB_READ	0x0
 22#define XRS_IB_WRITE	0x1
 23
 24static int xrs700x_mdio_reg_read(void *context, unsigned int reg,
 25				 unsigned int *val)
 26{
 27	struct mdio_device *mdiodev = context;
 28	struct device *dev = &mdiodev->dev;
 29	u16 uval;
 30	int ret;
 31
 32	uval = (u16)FIELD_GET(GENMASK(31, 16), reg);
 33
 34	ret = mdiodev_write(mdiodev, XRS_MDIO_IBA1, uval);
 35	if (ret < 0) {
 36		dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
 37		return ret;
 38	}
 39
 40	uval = (u16)((reg & GENMASK(15, 1)) | XRS_IB_READ);
 41
 42	ret = mdiodev_write(mdiodev, XRS_MDIO_IBA0, uval);
 43	if (ret < 0) {
 44		dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
 45		return ret;
 46	}
 47
 48	ret = mdiodev_read(mdiodev, XRS_MDIO_IBD);
 49	if (ret < 0) {
 50		dev_err(dev, "xrs mdiobus_read returned %d\n", ret);
 51		return ret;
 52	}
 53
 54	*val = (unsigned int)ret;
 55
 56	return 0;
 57}
 58
 59static int xrs700x_mdio_reg_write(void *context, unsigned int reg,
 60				  unsigned int val)
 61{
 62	struct mdio_device *mdiodev = context;
 63	struct device *dev = &mdiodev->dev;
 64	u16 uval;
 65	int ret;
 66
 67	ret = mdiodev_write(mdiodev, XRS_MDIO_IBD, (u16)val);
 68	if (ret < 0) {
 69		dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
 70		return ret;
 71	}
 72
 73	uval = (u16)FIELD_GET(GENMASK(31, 16), reg);
 74
 75	ret = mdiodev_write(mdiodev, XRS_MDIO_IBA1, uval);
 76	if (ret < 0) {
 77		dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
 78		return ret;
 79	}
 80
 81	uval = (u16)((reg & GENMASK(15, 1)) | XRS_IB_WRITE);
 82
 83	ret = mdiodev_write(mdiodev, XRS_MDIO_IBA0, uval);
 84	if (ret < 0) {
 85		dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
 86		return ret;
 87	}
 88
 89	return 0;
 90}
 91
 92static const struct regmap_config xrs700x_mdio_regmap_config = {
 93	.val_bits = 16,
 94	.reg_stride = 2,
 95	.reg_bits = 32,
 96	.pad_bits = 0,
 97	.write_flag_mask = 0,
 98	.read_flag_mask = 0,
 99	.reg_read = xrs700x_mdio_reg_read,
100	.reg_write = xrs700x_mdio_reg_write,
101	.max_register = XRS_VLAN(VLAN_N_VID - 1),
102	.cache_type = REGCACHE_NONE,
103	.reg_format_endian = REGMAP_ENDIAN_BIG,
104	.val_format_endian = REGMAP_ENDIAN_BIG
105};
106
107static int xrs700x_mdio_probe(struct mdio_device *mdiodev)
108{
109	struct xrs700x *priv;
110	int ret;
111
112	priv = xrs700x_switch_alloc(&mdiodev->dev, mdiodev);
113	if (!priv)
114		return -ENOMEM;
115
116	priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, mdiodev,
117					&xrs700x_mdio_regmap_config);
118	if (IS_ERR(priv->regmap)) {
119		ret = PTR_ERR(priv->regmap);
120		dev_err(&mdiodev->dev, "Failed to initialize regmap: %d\n", ret);
121		return ret;
122	}
123
124	dev_set_drvdata(&mdiodev->dev, priv);
125
126	ret = xrs700x_switch_register(priv);
127
128	/* Main DSA driver may not be started yet. */
129	if (ret)
130		return ret;
131
132	return 0;
133}
134
135static void xrs700x_mdio_remove(struct mdio_device *mdiodev)
136{
137	struct xrs700x *priv = dev_get_drvdata(&mdiodev->dev);
138
139	if (!priv)
140		return;
141
142	xrs700x_switch_remove(priv);
143}
144
145static void xrs700x_mdio_shutdown(struct mdio_device *mdiodev)
146{
147	struct xrs700x *priv = dev_get_drvdata(&mdiodev->dev);
148
149	if (!priv)
150		return;
151
152	xrs700x_switch_shutdown(priv);
153
154	dev_set_drvdata(&mdiodev->dev, NULL);
155}
156
157static const struct of_device_id __maybe_unused xrs700x_mdio_dt_ids[] = {
158	{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
159	{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
160	{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
161	{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
162	{},
163};
164MODULE_DEVICE_TABLE(of, xrs700x_mdio_dt_ids);
165
166static struct mdio_driver xrs700x_mdio_driver = {
167	.mdiodrv.driver = {
168		.name	= "xrs700x-mdio",
169		.of_match_table = of_match_ptr(xrs700x_mdio_dt_ids),
170	},
171	.probe	= xrs700x_mdio_probe,
172	.remove	= xrs700x_mdio_remove,
173	.shutdown = xrs700x_mdio_shutdown,
174};
175
176mdio_module_driver(xrs700x_mdio_driver);
177
178MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
179MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA MDIO driver");
180MODULE_LICENSE("GPL v2");