1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 NovaTech LLC
4 * George McCollister <george.mccollister@gmail.com>
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>
15 #include "xrs700x_reg.h"
17 #define XRS_MDIO_IBA0 0x10
18 #define XRS_MDIO_IBA1 0x11
19 #define XRS_MDIO_IBD 0x14
21 #define XRS_IB_READ 0x0
22 #define XRS_IB_WRITE 0x1
24 static int xrs700x_mdio_reg_read(void *context
, unsigned int reg
,
27 struct mdio_device
*mdiodev
= context
;
28 struct device
*dev
= &mdiodev
->dev
;
32 uval
= (u16
)FIELD_GET(GENMASK(31, 16), reg
);
34 ret
= mdiodev_write(mdiodev
, XRS_MDIO_IBA1
, uval
);
36 dev_err(dev
, "xrs mdiobus_write returned %d\n", ret
);
40 uval
= (u16
)((reg
& GENMASK(15, 1)) | XRS_IB_READ
);
42 ret
= mdiodev_write(mdiodev
, XRS_MDIO_IBA0
, uval
);
44 dev_err(dev
, "xrs mdiobus_write returned %d\n", ret
);
48 ret
= mdiodev_read(mdiodev
, XRS_MDIO_IBD
);
50 dev_err(dev
, "xrs mdiobus_read returned %d\n", ret
);
54 *val
= (unsigned int)ret
;
59 static int xrs700x_mdio_reg_write(void *context
, unsigned int reg
,
62 struct mdio_device
*mdiodev
= context
;
63 struct device
*dev
= &mdiodev
->dev
;
67 ret
= mdiodev_write(mdiodev
, XRS_MDIO_IBD
, (u16
)val
);
69 dev_err(dev
, "xrs mdiobus_write returned %d\n", ret
);
73 uval
= (u16
)FIELD_GET(GENMASK(31, 16), reg
);
75 ret
= mdiodev_write(mdiodev
, XRS_MDIO_IBA1
, uval
);
77 dev_err(dev
, "xrs mdiobus_write returned %d\n", ret
);
81 uval
= (u16
)((reg
& GENMASK(15, 1)) | XRS_IB_WRITE
);
83 ret
= mdiodev_write(mdiodev
, XRS_MDIO_IBA0
, uval
);
85 dev_err(dev
, "xrs mdiobus_write returned %d\n", ret
);
92 static const struct regmap_config xrs700x_mdio_regmap_config
= {
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
107 static int xrs700x_mdio_probe(struct mdio_device
*mdiodev
)
109 struct xrs700x
*priv
;
112 priv
= xrs700x_switch_alloc(&mdiodev
->dev
, mdiodev
);
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
);
124 dev_set_drvdata(&mdiodev
->dev
, priv
);
126 ret
= xrs700x_switch_register(priv
);
128 /* Main DSA driver may not be started yet. */
135 static void xrs700x_mdio_remove(struct mdio_device
*mdiodev
)
137 struct xrs700x
*priv
= dev_get_drvdata(&mdiodev
->dev
);
142 xrs700x_switch_remove(priv
);
145 static void xrs700x_mdio_shutdown(struct mdio_device
*mdiodev
)
147 struct xrs700x
*priv
= dev_get_drvdata(&mdiodev
->dev
);
152 xrs700x_switch_shutdown(priv
);
154 dev_set_drvdata(&mdiodev
->dev
, NULL
);
157 static 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
},
164 MODULE_DEVICE_TABLE(of
, xrs700x_mdio_dt_ids
);
166 static struct mdio_driver xrs700x_mdio_driver
= {
168 .name
= "xrs700x-mdio",
169 .of_match_table
= of_match_ptr(xrs700x_mdio_dt_ids
),
171 .probe
= xrs700x_mdio_probe
,
172 .remove
= xrs700x_mdio_remove
,
173 .shutdown
= xrs700x_mdio_shutdown
,
176 mdio_module_driver(xrs700x_mdio_driver
);
178 MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
179 MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA MDIO driver");
180 MODULE_LICENSE("GPL v2");