1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /* Realtek Simple Management Interface (SMI) driver
3*4882a593Smuzhiyun * It can be discussed how "simple" this interface is.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * The SMI protocol piggy-backs the MDIO MDC and MDIO signals levels
6*4882a593Smuzhiyun * but the protocol is not MDIO at all. Instead it is a Realtek
7*4882a593Smuzhiyun * pecularity that need to bit-bang the lines in a special way to
8*4882a593Smuzhiyun * communicate with the switch.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * ASICs we intend to support with this driver:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * RTL8366 - The original version, apparently
13*4882a593Smuzhiyun * RTL8369 - Similar enough to have the same datsheet as RTL8366
14*4882a593Smuzhiyun * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite
15*4882a593Smuzhiyun * different register layout from the other two
16*4882a593Smuzhiyun * RTL8366S - Is this "RTL8366 super"?
17*4882a593Smuzhiyun * RTL8367 - Has an OpenWRT driver as well
18*4882a593Smuzhiyun * RTL8368S - Seems to be an alternative name for RTL8366RB
19*4882a593Smuzhiyun * RTL8370 - Also uses SMI
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
22*4882a593Smuzhiyun * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
23*4882a593Smuzhiyun * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
24*4882a593Smuzhiyun * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
25*4882a593Smuzhiyun * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun #include <linux/module.h>
30*4882a593Smuzhiyun #include <linux/device.h>
31*4882a593Smuzhiyun #include <linux/spinlock.h>
32*4882a593Smuzhiyun #include <linux/skbuff.h>
33*4882a593Smuzhiyun #include <linux/of.h>
34*4882a593Smuzhiyun #include <linux/of_device.h>
35*4882a593Smuzhiyun #include <linux/of_mdio.h>
36*4882a593Smuzhiyun #include <linux/delay.h>
37*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
38*4882a593Smuzhiyun #include <linux/platform_device.h>
39*4882a593Smuzhiyun #include <linux/regmap.h>
40*4882a593Smuzhiyun #include <linux/bitops.h>
41*4882a593Smuzhiyun #include <linux/if_bridge.h>
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #include "realtek-smi-core.h"
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define REALTEK_SMI_ACK_RETRY_COUNT 5
46*4882a593Smuzhiyun #define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */
47*4882a593Smuzhiyun #define REALTEK_SMI_HW_START_DELAY 100 /* msecs */
48*4882a593Smuzhiyun
realtek_smi_clk_delay(struct realtek_smi * smi)49*4882a593Smuzhiyun static inline void realtek_smi_clk_delay(struct realtek_smi *smi)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun ndelay(smi->clk_delay);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
realtek_smi_start(struct realtek_smi * smi)54*4882a593Smuzhiyun static void realtek_smi_start(struct realtek_smi *smi)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun /* Set GPIO pins to output mode, with initial state:
57*4882a593Smuzhiyun * SCK = 0, SDA = 1
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun gpiod_direction_output(smi->mdc, 0);
60*4882a593Smuzhiyun gpiod_direction_output(smi->mdio, 1);
61*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* CLK 1: 0 -> 1, 1 -> 0 */
64*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
65*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
66*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
67*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* CLK 2: */
70*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
71*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
72*4882a593Smuzhiyun gpiod_set_value(smi->mdio, 0);
73*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
74*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
75*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
76*4882a593Smuzhiyun gpiod_set_value(smi->mdio, 1);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
realtek_smi_stop(struct realtek_smi * smi)79*4882a593Smuzhiyun static void realtek_smi_stop(struct realtek_smi *smi)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
82*4882a593Smuzhiyun gpiod_set_value(smi->mdio, 0);
83*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
84*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
85*4882a593Smuzhiyun gpiod_set_value(smi->mdio, 1);
86*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
87*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
88*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
89*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
90*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
91*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /* Add a click */
94*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
95*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
96*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
97*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* Set GPIO pins to input mode */
100*4882a593Smuzhiyun gpiod_direction_input(smi->mdio);
101*4882a593Smuzhiyun gpiod_direction_input(smi->mdc);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
realtek_smi_write_bits(struct realtek_smi * smi,u32 data,u32 len)104*4882a593Smuzhiyun static void realtek_smi_write_bits(struct realtek_smi *smi, u32 data, u32 len)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun for (; len > 0; len--) {
107*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* Prepare data */
110*4882a593Smuzhiyun gpiod_set_value(smi->mdio, !!(data & (1 << (len - 1))));
111*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* Clocking */
114*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
115*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
116*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
realtek_smi_read_bits(struct realtek_smi * smi,u32 len,u32 * data)120*4882a593Smuzhiyun static void realtek_smi_read_bits(struct realtek_smi *smi, u32 len, u32 *data)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun gpiod_direction_input(smi->mdio);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun for (*data = 0; len > 0; len--) {
125*4882a593Smuzhiyun u32 u;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* Clocking */
130*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 1);
131*4882a593Smuzhiyun realtek_smi_clk_delay(smi);
132*4882a593Smuzhiyun u = !!gpiod_get_value(smi->mdio);
133*4882a593Smuzhiyun gpiod_set_value(smi->mdc, 0);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun *data |= (u << (len - 1));
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun gpiod_direction_output(smi->mdio, 0);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
realtek_smi_wait_for_ack(struct realtek_smi * smi)141*4882a593Smuzhiyun static int realtek_smi_wait_for_ack(struct realtek_smi *smi)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun int retry_cnt;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun retry_cnt = 0;
146*4882a593Smuzhiyun do {
147*4882a593Smuzhiyun u32 ack;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun realtek_smi_read_bits(smi, 1, &ack);
150*4882a593Smuzhiyun if (ack == 0)
151*4882a593Smuzhiyun break;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (++retry_cnt > REALTEK_SMI_ACK_RETRY_COUNT) {
154*4882a593Smuzhiyun dev_err(smi->dev, "ACK timeout\n");
155*4882a593Smuzhiyun return -ETIMEDOUT;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun } while (1);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
realtek_smi_write_byte(struct realtek_smi * smi,u8 data)162*4882a593Smuzhiyun static int realtek_smi_write_byte(struct realtek_smi *smi, u8 data)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun realtek_smi_write_bits(smi, data, 8);
165*4882a593Smuzhiyun return realtek_smi_wait_for_ack(smi);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
realtek_smi_write_byte_noack(struct realtek_smi * smi,u8 data)168*4882a593Smuzhiyun static int realtek_smi_write_byte_noack(struct realtek_smi *smi, u8 data)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun realtek_smi_write_bits(smi, data, 8);
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
realtek_smi_read_byte0(struct realtek_smi * smi,u8 * data)174*4882a593Smuzhiyun static int realtek_smi_read_byte0(struct realtek_smi *smi, u8 *data)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun u32 t;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Read data */
179*4882a593Smuzhiyun realtek_smi_read_bits(smi, 8, &t);
180*4882a593Smuzhiyun *data = (t & 0xff);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Send an ACK */
183*4882a593Smuzhiyun realtek_smi_write_bits(smi, 0x00, 1);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
realtek_smi_read_byte1(struct realtek_smi * smi,u8 * data)188*4882a593Smuzhiyun static int realtek_smi_read_byte1(struct realtek_smi *smi, u8 *data)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun u32 t;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /* Read data */
193*4882a593Smuzhiyun realtek_smi_read_bits(smi, 8, &t);
194*4882a593Smuzhiyun *data = (t & 0xff);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* Send an ACK */
197*4882a593Smuzhiyun realtek_smi_write_bits(smi, 0x01, 1);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun return 0;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
realtek_smi_read_reg(struct realtek_smi * smi,u32 addr,u32 * data)202*4882a593Smuzhiyun static int realtek_smi_read_reg(struct realtek_smi *smi, u32 addr, u32 *data)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun unsigned long flags;
205*4882a593Smuzhiyun u8 lo = 0;
206*4882a593Smuzhiyun u8 hi = 0;
207*4882a593Smuzhiyun int ret;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun spin_lock_irqsave(&smi->lock, flags);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun realtek_smi_start(smi);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* Send READ command */
214*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, smi->cmd_read);
215*4882a593Smuzhiyun if (ret)
216*4882a593Smuzhiyun goto out;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* Set ADDR[7:0] */
219*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, addr & 0xff);
220*4882a593Smuzhiyun if (ret)
221*4882a593Smuzhiyun goto out;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Set ADDR[15:8] */
224*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, addr >> 8);
225*4882a593Smuzhiyun if (ret)
226*4882a593Smuzhiyun goto out;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /* Read DATA[7:0] */
229*4882a593Smuzhiyun realtek_smi_read_byte0(smi, &lo);
230*4882a593Smuzhiyun /* Read DATA[15:8] */
231*4882a593Smuzhiyun realtek_smi_read_byte1(smi, &hi);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun *data = ((u32)lo) | (((u32)hi) << 8);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun ret = 0;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun out:
238*4882a593Smuzhiyun realtek_smi_stop(smi);
239*4882a593Smuzhiyun spin_unlock_irqrestore(&smi->lock, flags);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun return ret;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
realtek_smi_write_reg(struct realtek_smi * smi,u32 addr,u32 data,bool ack)244*4882a593Smuzhiyun static int realtek_smi_write_reg(struct realtek_smi *smi,
245*4882a593Smuzhiyun u32 addr, u32 data, bool ack)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun unsigned long flags;
248*4882a593Smuzhiyun int ret;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun spin_lock_irqsave(&smi->lock, flags);
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun realtek_smi_start(smi);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* Send WRITE command */
255*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, smi->cmd_write);
256*4882a593Smuzhiyun if (ret)
257*4882a593Smuzhiyun goto out;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* Set ADDR[7:0] */
260*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, addr & 0xff);
261*4882a593Smuzhiyun if (ret)
262*4882a593Smuzhiyun goto out;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* Set ADDR[15:8] */
265*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, addr >> 8);
266*4882a593Smuzhiyun if (ret)
267*4882a593Smuzhiyun goto out;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* Write DATA[7:0] */
270*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, data & 0xff);
271*4882a593Smuzhiyun if (ret)
272*4882a593Smuzhiyun goto out;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* Write DATA[15:8] */
275*4882a593Smuzhiyun if (ack)
276*4882a593Smuzhiyun ret = realtek_smi_write_byte(smi, data >> 8);
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun ret = realtek_smi_write_byte_noack(smi, data >> 8);
279*4882a593Smuzhiyun if (ret)
280*4882a593Smuzhiyun goto out;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun ret = 0;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun out:
285*4882a593Smuzhiyun realtek_smi_stop(smi);
286*4882a593Smuzhiyun spin_unlock_irqrestore(&smi->lock, flags);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return ret;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* There is one single case when we need to use this accessor and that
292*4882a593Smuzhiyun * is when issueing soft reset. Since the device reset as soon as we write
293*4882a593Smuzhiyun * that bit, no ACK will come back for natural reasons.
294*4882a593Smuzhiyun */
realtek_smi_write_reg_noack(struct realtek_smi * smi,u32 addr,u32 data)295*4882a593Smuzhiyun int realtek_smi_write_reg_noack(struct realtek_smi *smi, u32 addr,
296*4882a593Smuzhiyun u32 data)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun return realtek_smi_write_reg(smi, addr, data, false);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(realtek_smi_write_reg_noack);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Regmap accessors */
303*4882a593Smuzhiyun
realtek_smi_write(void * ctx,u32 reg,u32 val)304*4882a593Smuzhiyun static int realtek_smi_write(void *ctx, u32 reg, u32 val)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun struct realtek_smi *smi = ctx;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return realtek_smi_write_reg(smi, reg, val, true);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
realtek_smi_read(void * ctx,u32 reg,u32 * val)311*4882a593Smuzhiyun static int realtek_smi_read(void *ctx, u32 reg, u32 *val)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun struct realtek_smi *smi = ctx;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return realtek_smi_read_reg(smi, reg, val);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun static const struct regmap_config realtek_smi_mdio_regmap_config = {
319*4882a593Smuzhiyun .reg_bits = 10, /* A4..A0 R4..R0 */
320*4882a593Smuzhiyun .val_bits = 16,
321*4882a593Smuzhiyun .reg_stride = 1,
322*4882a593Smuzhiyun /* PHY regs are at 0x8000 */
323*4882a593Smuzhiyun .max_register = 0xffff,
324*4882a593Smuzhiyun .reg_format_endian = REGMAP_ENDIAN_BIG,
325*4882a593Smuzhiyun .reg_read = realtek_smi_read,
326*4882a593Smuzhiyun .reg_write = realtek_smi_write,
327*4882a593Smuzhiyun .cache_type = REGCACHE_NONE,
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun
realtek_smi_mdio_read(struct mii_bus * bus,int addr,int regnum)330*4882a593Smuzhiyun static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun struct realtek_smi *smi = bus->priv;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun return smi->ops->phy_read(smi, addr, regnum);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
realtek_smi_mdio_write(struct mii_bus * bus,int addr,int regnum,u16 val)337*4882a593Smuzhiyun static int realtek_smi_mdio_write(struct mii_bus *bus, int addr, int regnum,
338*4882a593Smuzhiyun u16 val)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct realtek_smi *smi = bus->priv;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun return smi->ops->phy_write(smi, addr, regnum, val);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
realtek_smi_setup_mdio(struct realtek_smi * smi)345*4882a593Smuzhiyun int realtek_smi_setup_mdio(struct realtek_smi *smi)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct device_node *mdio_np;
348*4882a593Smuzhiyun int ret;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun mdio_np = of_get_compatible_child(smi->dev->of_node, "realtek,smi-mdio");
351*4882a593Smuzhiyun if (!mdio_np) {
352*4882a593Smuzhiyun dev_err(smi->dev, "no MDIO bus node\n");
353*4882a593Smuzhiyun return -ENODEV;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun smi->slave_mii_bus = devm_mdiobus_alloc(smi->dev);
357*4882a593Smuzhiyun if (!smi->slave_mii_bus) {
358*4882a593Smuzhiyun ret = -ENOMEM;
359*4882a593Smuzhiyun goto err_put_node;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun smi->slave_mii_bus->priv = smi;
362*4882a593Smuzhiyun smi->slave_mii_bus->name = "SMI slave MII";
363*4882a593Smuzhiyun smi->slave_mii_bus->read = realtek_smi_mdio_read;
364*4882a593Smuzhiyun smi->slave_mii_bus->write = realtek_smi_mdio_write;
365*4882a593Smuzhiyun snprintf(smi->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d",
366*4882a593Smuzhiyun smi->ds->index);
367*4882a593Smuzhiyun smi->slave_mii_bus->dev.of_node = mdio_np;
368*4882a593Smuzhiyun smi->slave_mii_bus->parent = smi->dev;
369*4882a593Smuzhiyun smi->ds->slave_mii_bus = smi->slave_mii_bus;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ret = devm_of_mdiobus_register(smi->dev, smi->slave_mii_bus, mdio_np);
372*4882a593Smuzhiyun if (ret) {
373*4882a593Smuzhiyun dev_err(smi->dev, "unable to register MDIO bus %s\n",
374*4882a593Smuzhiyun smi->slave_mii_bus->id);
375*4882a593Smuzhiyun goto err_put_node;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun err_put_node:
381*4882a593Smuzhiyun of_node_put(mdio_np);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return ret;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
realtek_smi_probe(struct platform_device * pdev)386*4882a593Smuzhiyun static int realtek_smi_probe(struct platform_device *pdev)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun const struct realtek_smi_variant *var;
389*4882a593Smuzhiyun struct device *dev = &pdev->dev;
390*4882a593Smuzhiyun struct realtek_smi *smi;
391*4882a593Smuzhiyun struct device_node *np;
392*4882a593Smuzhiyun int ret;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun var = of_device_get_match_data(dev);
395*4882a593Smuzhiyun np = dev->of_node;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun smi = devm_kzalloc(dev, sizeof(*smi) + var->chip_data_sz, GFP_KERNEL);
398*4882a593Smuzhiyun if (!smi)
399*4882a593Smuzhiyun return -ENOMEM;
400*4882a593Smuzhiyun smi->chip_data = (void *)smi + sizeof(*smi);
401*4882a593Smuzhiyun smi->map = devm_regmap_init(dev, NULL, smi,
402*4882a593Smuzhiyun &realtek_smi_mdio_regmap_config);
403*4882a593Smuzhiyun if (IS_ERR(smi->map)) {
404*4882a593Smuzhiyun ret = PTR_ERR(smi->map);
405*4882a593Smuzhiyun dev_err(dev, "regmap init failed: %d\n", ret);
406*4882a593Smuzhiyun return ret;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* Link forward and backward */
410*4882a593Smuzhiyun smi->dev = dev;
411*4882a593Smuzhiyun smi->clk_delay = var->clk_delay;
412*4882a593Smuzhiyun smi->cmd_read = var->cmd_read;
413*4882a593Smuzhiyun smi->cmd_write = var->cmd_write;
414*4882a593Smuzhiyun smi->ops = var->ops;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun dev_set_drvdata(dev, smi);
417*4882a593Smuzhiyun spin_lock_init(&smi->lock);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /* TODO: if power is software controlled, set up any regulators here */
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /* Assert then deassert RESET */
422*4882a593Smuzhiyun smi->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
423*4882a593Smuzhiyun if (IS_ERR(smi->reset)) {
424*4882a593Smuzhiyun dev_err(dev, "failed to get RESET GPIO\n");
425*4882a593Smuzhiyun return PTR_ERR(smi->reset);
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun msleep(REALTEK_SMI_HW_STOP_DELAY);
428*4882a593Smuzhiyun gpiod_set_value(smi->reset, 0);
429*4882a593Smuzhiyun msleep(REALTEK_SMI_HW_START_DELAY);
430*4882a593Smuzhiyun dev_info(dev, "deasserted RESET\n");
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /* Fetch MDIO pins */
433*4882a593Smuzhiyun smi->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW);
434*4882a593Smuzhiyun if (IS_ERR(smi->mdc))
435*4882a593Smuzhiyun return PTR_ERR(smi->mdc);
436*4882a593Smuzhiyun smi->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW);
437*4882a593Smuzhiyun if (IS_ERR(smi->mdio))
438*4882a593Smuzhiyun return PTR_ERR(smi->mdio);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun smi->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun ret = smi->ops->detect(smi);
443*4882a593Smuzhiyun if (ret) {
444*4882a593Smuzhiyun dev_err(dev, "unable to detect switch\n");
445*4882a593Smuzhiyun return ret;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun smi->ds = devm_kzalloc(dev, sizeof(*smi->ds), GFP_KERNEL);
449*4882a593Smuzhiyun if (!smi->ds)
450*4882a593Smuzhiyun return -ENOMEM;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun smi->ds->dev = dev;
453*4882a593Smuzhiyun smi->ds->num_ports = smi->num_ports;
454*4882a593Smuzhiyun smi->ds->priv = smi;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun smi->ds->ops = var->ds_ops;
457*4882a593Smuzhiyun ret = dsa_register_switch(smi->ds);
458*4882a593Smuzhiyun if (ret) {
459*4882a593Smuzhiyun dev_err(dev, "unable to register switch ret = %d\n", ret);
460*4882a593Smuzhiyun return ret;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
realtek_smi_remove(struct platform_device * pdev)465*4882a593Smuzhiyun static int realtek_smi_remove(struct platform_device *pdev)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun struct realtek_smi *smi = dev_get_drvdata(&pdev->dev);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun dsa_unregister_switch(smi->ds);
470*4882a593Smuzhiyun if (smi->slave_mii_bus)
471*4882a593Smuzhiyun of_node_put(smi->slave_mii_bus->dev.of_node);
472*4882a593Smuzhiyun gpiod_set_value(smi->reset, 1);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun return 0;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun static const struct of_device_id realtek_smi_of_match[] = {
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun .compatible = "realtek,rtl8366rb",
480*4882a593Smuzhiyun .data = &rtl8366rb_variant,
481*4882a593Smuzhiyun },
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun /* FIXME: add support for RTL8366S and more */
484*4882a593Smuzhiyun .compatible = "realtek,rtl8366s",
485*4882a593Smuzhiyun .data = NULL,
486*4882a593Smuzhiyun },
487*4882a593Smuzhiyun { /* sentinel */ },
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, realtek_smi_of_match);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun static struct platform_driver realtek_smi_driver = {
492*4882a593Smuzhiyun .driver = {
493*4882a593Smuzhiyun .name = "realtek-smi",
494*4882a593Smuzhiyun .of_match_table = of_match_ptr(realtek_smi_of_match),
495*4882a593Smuzhiyun },
496*4882a593Smuzhiyun .probe = realtek_smi_probe,
497*4882a593Smuzhiyun .remove = realtek_smi_remove,
498*4882a593Smuzhiyun };
499*4882a593Smuzhiyun module_platform_driver(realtek_smi_driver);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun MODULE_LICENSE("GPL");
502