33 * MDIO I2C bridge
44 *
55 * Copyright (C) 2015-2016 Russell King
6+ * Copyright (C) 2021 Marek Behun
67 *
78 * Network PHYs can appear on I2C buses when they are part of SFP module.
89 * This driver exposes these PHYs to the networking PHY code, allowing
1213#include <linux/i2c.h>
1314#include <linux/mdio/mdio-i2c.h>
1415#include <linux/phy.h>
16+ #include <linux/sfp.h>
1517
1618/*
1719 * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
@@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id)
2830 return phy_id + 0x40 ;
2931}
3032
31- static int i2c_mii_read (struct mii_bus * bus , int phy_id , int reg )
33+ static int i2c_mii_read_default (struct mii_bus * bus , int phy_id , int reg )
3234{
3335 struct i2c_adapter * i2c = bus -> priv ;
3436 struct i2c_msg msgs [2 ];
@@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg)
6264 return data [0 ] << 8 | data [1 ];
6365}
6466
65- static int i2c_mii_write (struct mii_bus * bus , int phy_id , int reg , u16 val )
67+ static int i2c_mii_write_default (struct mii_bus * bus , int phy_id , int reg ,
68+ u16 val )
6669{
6770 struct i2c_adapter * i2c = bus -> priv ;
6871 struct i2c_msg msg ;
@@ -91,9 +94,288 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
9194 return ret < 0 ? ret : 0 ;
9295}
9396
94- struct mii_bus * mdio_i2c_alloc (struct device * parent , struct i2c_adapter * i2c )
97+ /* RollBall SFPs do not access internal PHY via I2C address 0x56, but
98+ * instead via address 0x51, when SFP page is set to 0x03 and password to
99+ * 0xffffffff.
100+ *
101+ * address size contents description
102+ * ------- ---- -------- -----------
103+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done
104+ * 0x81 1 DEV Clause 45 device
105+ * 0x82 2 REG Clause 45 register
106+ * 0x84 2 VAL Register value
107+ */
108+ #define ROLLBALL_PHY_I2C_ADDR 0x51
109+
110+ #define ROLLBALL_PASSWORD (SFP_VSL + 3)
111+
112+ #define ROLLBALL_CMD_ADDR 0x80
113+ #define ROLLBALL_DATA_ADDR 0x81
114+
115+ #define ROLLBALL_CMD_WRITE 0x01
116+ #define ROLLBALL_CMD_READ 0x02
117+ #define ROLLBALL_CMD_DONE 0x04
118+
119+ #define SFP_PAGE_ROLLBALL_MDIO 3
120+
121+ static int __i2c_transfer_err (struct i2c_adapter * i2c , struct i2c_msg * msgs ,
122+ int num )
123+ {
124+ int ret ;
125+
126+ ret = __i2c_transfer (i2c , msgs , num );
127+ if (ret < 0 )
128+ return ret ;
129+ else if (ret != num )
130+ return - EIO ;
131+ else
132+ return 0 ;
133+ }
134+
135+ static int __i2c_rollball_get_page (struct i2c_adapter * i2c , int bus_addr ,
136+ u8 * page )
137+ {
138+ struct i2c_msg msgs [2 ];
139+ u8 addr = SFP_PAGE ;
140+
141+ msgs [0 ].addr = bus_addr ;
142+ msgs [0 ].flags = 0 ;
143+ msgs [0 ].len = 1 ;
144+ msgs [0 ].buf = & addr ;
145+
146+ msgs [1 ].addr = bus_addr ;
147+ msgs [1 ].flags = I2C_M_RD ;
148+ msgs [1 ].len = 1 ;
149+ msgs [1 ].buf = page ;
150+
151+ return __i2c_transfer_err (i2c , msgs , 2 );
152+ }
153+
154+ static int __i2c_rollball_set_page (struct i2c_adapter * i2c , int bus_addr ,
155+ u8 page )
156+ {
157+ struct i2c_msg msg ;
158+ u8 buf [2 ];
159+
160+ buf [0 ] = SFP_PAGE ;
161+ buf [1 ] = page ;
162+
163+ msg .addr = bus_addr ;
164+ msg .flags = 0 ;
165+ msg .len = 2 ;
166+ msg .buf = buf ;
167+
168+ return __i2c_transfer_err (i2c , & msg , 1 );
169+ }
170+
171+ /* In order to not interfere with other SFP code (which possibly may manipulate
172+ * SFP_PAGE), for every transfer we do this:
173+ * 1. lock the bus
174+ * 2. save content of SFP_PAGE
175+ * 3. set SFP_PAGE to 3
176+ * 4. do the transfer
177+ * 5. restore original SFP_PAGE
178+ * 6. unlock the bus
179+ * Note that one might think that steps 2 to 5 could be theoretically done all
180+ * in one call to i2c_transfer (by constructing msgs array in such a way), but
181+ * unfortunately tests show that this does not work :-( Changed SFP_PAGE does
182+ * not take into account until i2c_transfer() is done.
183+ */
184+ static int i2c_transfer_rollball (struct i2c_adapter * i2c ,
185+ struct i2c_msg * msgs , int num )
186+ {
187+ int ret , main_err = 0 ;
188+ u8 saved_page ;
189+
190+ i2c_lock_bus (i2c , I2C_LOCK_SEGMENT );
191+
192+ /* save original page */
193+ ret = __i2c_rollball_get_page (i2c , msgs -> addr , & saved_page );
194+ if (ret )
195+ goto unlock ;
196+
197+ /* change to RollBall MDIO page */
198+ ret = __i2c_rollball_set_page (i2c , msgs -> addr , SFP_PAGE_ROLLBALL_MDIO );
199+ if (ret )
200+ goto unlock ;
201+
202+ /* do the transfer; we try to restore original page if this fails */
203+ ret = __i2c_transfer_err (i2c , msgs , num );
204+ if (ret )
205+ main_err = ret ;
206+
207+ /* restore original page */
208+ ret = __i2c_rollball_set_page (i2c , msgs -> addr , saved_page );
209+
210+ unlock :
211+ i2c_unlock_bus (i2c , I2C_LOCK_SEGMENT );
212+
213+ return main_err ? : ret ;
214+ }
215+
216+ static int i2c_rollball_mii_poll (struct mii_bus * bus , int bus_addr , u8 * buf ,
217+ size_t len )
218+ {
219+ struct i2c_adapter * i2c = bus -> priv ;
220+ struct i2c_msg msgs [2 ];
221+ u8 cmd_addr , tmp , * res ;
222+ int i , ret ;
223+
224+ cmd_addr = ROLLBALL_CMD_ADDR ;
225+
226+ res = buf ? buf : & tmp ;
227+ len = buf ? len : 1 ;
228+
229+ msgs [0 ].addr = bus_addr ;
230+ msgs [0 ].flags = 0 ;
231+ msgs [0 ].len = 1 ;
232+ msgs [0 ].buf = & cmd_addr ;
233+
234+ msgs [1 ].addr = bus_addr ;
235+ msgs [1 ].flags = I2C_M_RD ;
236+ msgs [1 ].len = len ;
237+ msgs [1 ].buf = res ;
238+
239+ /* By experiment it takes up to 70 ms to access a register for these
240+ * SFPs. Sleep 20ms between iterations and try 10 times.
241+ */
242+ i = 10 ;
243+ do {
244+ msleep (20 );
245+
246+ ret = i2c_transfer_rollball (i2c , msgs , ARRAY_SIZE (msgs ));
247+ if (ret )
248+ return ret ;
249+
250+ if (* res == ROLLBALL_CMD_DONE )
251+ return 0 ;
252+ } while (i -- > 0 );
253+
254+ dev_dbg (& bus -> dev , "poll timed out\n" );
255+
256+ return - ETIMEDOUT ;
257+ }
258+
259+ static int i2c_rollball_mii_cmd (struct mii_bus * bus , int bus_addr , u8 cmd ,
260+ u8 * data , size_t len )
261+ {
262+ struct i2c_adapter * i2c = bus -> priv ;
263+ struct i2c_msg msgs [2 ];
264+ u8 cmdbuf [2 ];
265+
266+ cmdbuf [0 ] = ROLLBALL_CMD_ADDR ;
267+ cmdbuf [1 ] = cmd ;
268+
269+ msgs [0 ].addr = bus_addr ;
270+ msgs [0 ].flags = 0 ;
271+ msgs [0 ].len = len ;
272+ msgs [0 ].buf = data ;
273+
274+ msgs [1 ].addr = bus_addr ;
275+ msgs [1 ].flags = 0 ;
276+ msgs [1 ].len = sizeof (cmdbuf );
277+ msgs [1 ].buf = cmdbuf ;
278+
279+ return i2c_transfer_rollball (i2c , msgs , ARRAY_SIZE (msgs ));
280+ }
281+
282+ static int i2c_mii_read_rollball (struct mii_bus * bus , int phy_id , int reg )
283+ {
284+ u8 buf [4 ], res [6 ];
285+ int bus_addr , ret ;
286+ u16 val ;
287+
288+ if (!(reg & MII_ADDR_C45 ))
289+ return - EOPNOTSUPP ;
290+
291+ bus_addr = i2c_mii_phy_addr (phy_id );
292+ if (bus_addr != ROLLBALL_PHY_I2C_ADDR )
293+ return 0xffff ;
294+
295+ buf [0 ] = ROLLBALL_DATA_ADDR ;
296+ buf [1 ] = (reg >> 16 ) & 0x1f ;
297+ buf [2 ] = (reg >> 8 ) & 0xff ;
298+ buf [3 ] = reg & 0xff ;
299+
300+ ret = i2c_rollball_mii_cmd (bus , bus_addr , ROLLBALL_CMD_READ , buf ,
301+ sizeof (buf ));
302+ if (ret < 0 )
303+ return ret ;
304+
305+ ret = i2c_rollball_mii_poll (bus , bus_addr , res , sizeof (res ));
306+ if (ret == - ETIMEDOUT )
307+ return 0xffff ;
308+ else if (ret < 0 )
309+ return ret ;
310+
311+ val = res [4 ] << 8 | res [5 ];
312+
313+ return val ;
314+ }
315+
316+ static int i2c_mii_write_rollball (struct mii_bus * bus , int phy_id , int reg ,
317+ u16 val )
318+ {
319+ int bus_addr , ret ;
320+ u8 buf [6 ];
321+
322+ if (!(reg & MII_ADDR_C45 ))
323+ return - EOPNOTSUPP ;
324+
325+ bus_addr = i2c_mii_phy_addr (phy_id );
326+ if (bus_addr != ROLLBALL_PHY_I2C_ADDR )
327+ return 0 ;
328+
329+ buf [0 ] = ROLLBALL_DATA_ADDR ;
330+ buf [1 ] = (reg >> 16 ) & 0x1f ;
331+ buf [2 ] = (reg >> 8 ) & 0xff ;
332+ buf [3 ] = reg & 0xff ;
333+ buf [4 ] = val >> 8 ;
334+ buf [5 ] = val & 0xff ;
335+
336+ ret = i2c_rollball_mii_cmd (bus , bus_addr , ROLLBALL_CMD_WRITE , buf ,
337+ sizeof (buf ));
338+ if (ret < 0 )
339+ return ret ;
340+
341+ ret = i2c_rollball_mii_poll (bus , bus_addr , NULL , 0 );
342+ if (ret < 0 )
343+ return ret ;
344+
345+ return 0 ;
346+ }
347+
348+ static int i2c_mii_init_rollball (struct i2c_adapter * i2c )
349+ {
350+ struct i2c_msg msg ;
351+ u8 pw [5 ];
352+ int ret ;
353+
354+ pw [0 ] = ROLLBALL_PASSWORD ;
355+ pw [1 ] = 0xff ;
356+ pw [2 ] = 0xff ;
357+ pw [3 ] = 0xff ;
358+ pw [4 ] = 0xff ;
359+
360+ msg .addr = ROLLBALL_PHY_I2C_ADDR ;
361+ msg .flags = 0 ;
362+ msg .len = sizeof (pw );
363+ msg .buf = pw ;
364+
365+ ret = i2c_transfer (i2c , & msg , 1 );
366+ if (ret < 0 )
367+ return ret ;
368+ else if (ret != 1 )
369+ return - EIO ;
370+ else
371+ return 0 ;
372+ }
373+
374+ struct mii_bus * mdio_i2c_alloc (struct device * parent , struct i2c_adapter * i2c ,
375+ enum mdio_i2c_proto protocol )
95376{
96377 struct mii_bus * mii ;
378+ int ret ;
97379
98380 if (!i2c_check_functionality (i2c , I2C_FUNC_I2C ))
99381 return ERR_PTR (- EINVAL );
@@ -104,10 +386,28 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c)
104386
105387 snprintf (mii -> id , MII_BUS_ID_SIZE , "i2c:%s" , dev_name (parent ));
106388 mii -> parent = parent ;
107- mii -> read = i2c_mii_read ;
108- mii -> write = i2c_mii_write ;
109389 mii -> priv = i2c ;
110390
391+ switch (protocol ) {
392+ case MDIO_I2C_ROLLBALL :
393+ ret = i2c_mii_init_rollball (i2c );
394+ if (ret < 0 ) {
395+ dev_err (parent ,
396+ "Cannot initialize RollBall MDIO I2C protocol: %d\n" ,
397+ ret );
398+ mdiobus_free (mii );
399+ return ERR_PTR (ret );
400+ }
401+
402+ mii -> read = i2c_mii_read_rollball ;
403+ mii -> write = i2c_mii_write_rollball ;
404+ break ;
405+ default :
406+ mii -> read = i2c_mii_read_default ;
407+ mii -> write = i2c_mii_write_default ;
408+ break ;
409+ }
410+
111411 return mii ;
112412}
113413EXPORT_SYMBOL_GPL (mdio_i2c_alloc );
0 commit comments