Skip to content

Commit dc70058

Browse files
jbeptxdavem330
authored andcommitted
net: dsa: LAN9303: add MDIO managed mode support
When the LAN9303 device is in MDIO manged mode, all register accesses must be done via MDIO. Please note: this code is compile time tested only due to the absence of such configured hardware. It is based on a patch from Stefan Roese from 2014. Signed-off-by: Juergen Borleis <[email protected]> CC: [email protected] CC: [email protected] CC: [email protected] CC: [email protected] Acked-by: Rob Herring <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent be4e119 commit dc70058

File tree

4 files changed

+201
-1
lines changed

4 files changed

+201
-1
lines changed

Documentation/devicetree/bindings/net/dsa/lan9303.txt

+44-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ SMSC/MicroChip LAN9303 three port ethernet switch
33

44
Required properties:
55

6-
- compatible: should be "smsc,lan9303-i2c"
6+
- compatible: should be
7+
- "smsc,lan9303-i2c" for I2C managed mode
8+
or
9+
- "smsc,lan9303-mdio" for mdio managed mode
710

811
Optional properties:
912

@@ -60,3 +63,43 @@ I2C managed mode:
6063
};
6164
};
6265
};
66+
67+
MDIO managed mode:
68+
69+
master: masterdevice@X {
70+
status = "okay";
71+
phy-handle = <&switch>;
72+
73+
mdio {
74+
#address-cells = <1>;
75+
#size-cells = <0>;
76+
77+
switch: switch-phy@0 {
78+
compatible = "smsc,lan9303-mdio";
79+
reg = <0>;
80+
reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
81+
reset-duration = <100>;
82+
83+
ports {
84+
#address-cells = <1>;
85+
#size-cells = <0>;
86+
87+
port@0 {
88+
reg = <0>;
89+
label = "cpu";
90+
ethernet = <&master>;
91+
};
92+
93+
port@1 { /* external port 1 */
94+
reg = <1>;
95+
label = "lan1;
96+
};
97+
98+
port@2 { /* external port 2 */
99+
reg = <2>;
100+
label = "lan2";
101+
};
102+
};
103+
};
104+
};
105+
};

drivers/net/dsa/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,12 @@ config NET_DSA_SMSC_LAN9303_I2C
6666
Enable access functions if the SMSC/Microchip LAN9303 is configured
6767
for I2C managed mode.
6868

69+
config NET_DSA_SMSC_LAN9303_MDIO
70+
tristate "SMSC/Microchip LAN9303 3-ports 10/100 ethernet switch in MDIO managed mode"
71+
depends on NET_DSA
72+
select NET_DSA_SMSC_LAN9303
73+
---help---
74+
Enable access functions if the SMSC/Microchip LAN9303 is configured
75+
for MDIO managed mode.
76+
6977
endmenu

drivers/net/dsa/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
55
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
66
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
77
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
8+
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
89
obj-y += b53/
910
obj-y += mv88e6xxx/
1011
obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o dsa_loop_bdinfo.o

drivers/net/dsa/lan9303_mdio.c

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright (C) 2017 Pengutronix, Juergen Borleis <[email protected]>
3+
*
4+
* Partially based on a patch from
5+
* Copyright (c) 2014 Stefan Roese <[email protected]>
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* version 2, as published by the Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
*/
17+
#include <linux/kernel.h>
18+
#include <linux/module.h>
19+
#include <linux/mdio.h>
20+
#include <linux/phy.h>
21+
#include <linux/of.h>
22+
23+
#include "lan9303.h"
24+
25+
/* Generate phy-addr and -reg from the input address */
26+
#define PHY_ADDR(x) ((((x) >> 6) + 0x10) & 0x1f)
27+
#define PHY_REG(x) (((x) >> 1) & 0x1f)
28+
29+
struct lan9303_mdio {
30+
struct mdio_device *device;
31+
struct lan9303 chip;
32+
};
33+
34+
static void lan9303_mdio_real_write(struct mdio_device *mdio, int reg, u16 val)
35+
{
36+
mdio->bus->write(mdio->bus, PHY_ADDR(reg), PHY_REG(reg), val);
37+
}
38+
39+
static int lan9303_mdio_write(void *ctx, uint32_t reg, uint32_t val)
40+
{
41+
struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
42+
43+
mutex_lock(&sw_dev->device->bus->mdio_lock);
44+
lan9303_mdio_real_write(sw_dev->device, reg, val & 0xffff);
45+
lan9303_mdio_real_write(sw_dev->device, reg + 2, (val >> 16) & 0xffff);
46+
mutex_unlock(&sw_dev->device->bus->mdio_lock);
47+
48+
return 0;
49+
}
50+
51+
static u16 lan9303_mdio_real_read(struct mdio_device *mdio, int reg)
52+
{
53+
return mdio->bus->read(mdio->bus, PHY_ADDR(reg), PHY_REG(reg));
54+
}
55+
56+
static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val)
57+
{
58+
struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
59+
60+
mutex_lock(&sw_dev->device->bus->mdio_lock);
61+
*val = lan9303_mdio_real_read(sw_dev->device, reg);
62+
*val |= (lan9303_mdio_real_read(sw_dev->device, reg + 2) << 16);
63+
mutex_unlock(&sw_dev->device->bus->mdio_lock);
64+
65+
return 0;
66+
}
67+
68+
static const struct regmap_config lan9303_mdio_regmap_config = {
69+
.reg_bits = 8,
70+
.val_bits = 32,
71+
.reg_stride = 1,
72+
.can_multi_write = true,
73+
.max_register = 0x0ff, /* address bits 0..1 are not used */
74+
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
75+
76+
.volatile_table = &lan9303_register_set,
77+
.wr_table = &lan9303_register_set,
78+
.rd_table = &lan9303_register_set,
79+
80+
.reg_read = lan9303_mdio_read,
81+
.reg_write = lan9303_mdio_write,
82+
83+
.cache_type = REGCACHE_NONE,
84+
};
85+
86+
static int lan9303_mdio_probe(struct mdio_device *mdiodev)
87+
{
88+
struct lan9303_mdio *sw_dev;
89+
int ret;
90+
91+
sw_dev = devm_kzalloc(&mdiodev->dev, sizeof(struct lan9303_mdio),
92+
GFP_KERNEL);
93+
if (!sw_dev)
94+
return -ENOMEM;
95+
96+
sw_dev->chip.regmap = devm_regmap_init(&mdiodev->dev, NULL, sw_dev,
97+
&lan9303_mdio_regmap_config);
98+
if (IS_ERR(sw_dev->chip.regmap)) {
99+
ret = PTR_ERR(sw_dev->chip.regmap);
100+
dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret);
101+
return ret;
102+
}
103+
104+
/* link forward and backward */
105+
sw_dev->device = mdiodev;
106+
dev_set_drvdata(&mdiodev->dev, sw_dev);
107+
sw_dev->chip.dev = &mdiodev->dev;
108+
109+
ret = lan9303_probe(&sw_dev->chip, mdiodev->dev.of_node);
110+
if (ret != 0)
111+
return ret;
112+
113+
dev_info(&mdiodev->dev, "LAN9303 MDIO driver loaded successfully\n");
114+
115+
return 0;
116+
}
117+
118+
static void lan9303_mdio_remove(struct mdio_device *mdiodev)
119+
{
120+
struct lan9303_mdio *sw_dev = dev_get_drvdata(&mdiodev->dev);
121+
122+
if (!sw_dev)
123+
return;
124+
125+
lan9303_remove(&sw_dev->chip);
126+
}
127+
128+
/*-------------------------------------------------------------------------*/
129+
130+
static const struct of_device_id lan9303_mdio_of_match[] = {
131+
{ .compatible = "smsc,lan9303-mdio" },
132+
{ /* sentinel */ },
133+
};
134+
MODULE_DEVICE_TABLE(of, lan9303_mdio_of_match);
135+
136+
static struct mdio_driver lan9303_mdio_driver = {
137+
.mdiodrv.driver = {
138+
.name = "LAN9303_MDIO",
139+
.of_match_table = of_match_ptr(lan9303_mdio_of_match),
140+
},
141+
.probe = lan9303_mdio_probe,
142+
.remove = lan9303_mdio_remove,
143+
};
144+
mdio_module_driver(lan9303_mdio_driver);
145+
146+
MODULE_AUTHOR("Stefan Roese <[email protected]>, Juergen Borleis <[email protected]>");
147+
MODULE_DESCRIPTION("Driver for SMSC/Microchip LAN9303 three port ethernet switch in MDIO managed mode");
148+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)