File Index
Files and directories
Sign in
FILE

mdio-i2c.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/mdio/mdio-i2c.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * MDIO I2C bridge
  4 *
  5 * Copyright (C) 2015-2016 Russell King
  6 * Copyright (C) 2021 Marek Behun
  7 *
  8 * Network PHYs can appear on I2C buses when they are part of SFP module.
  9 * This driver exposes these PHYs to the networking PHY code, allowing
 10 * our PHY drivers access to these PHYs, and so allowing configuration
 11 * of their settings.
 12 */
 13#include <linux/i2c.h>
 14#include <linux/mdio/mdio-i2c.h>
 15#include <linux/phy.h>
 16#include <linux/sfp.h>
 17
 18/*
 19 * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is
 20 * specified to be present in SFP modules.  These correspond with PHY
 21 * addresses 16 and 17.  Disallow access to these "phy" addresses.
 22 */
 23static bool i2c_mii_valid_phy_id(int phy_id)
 24{
 25	return phy_id != 0x10 && phy_id != 0x11;
 26}
 27
 28static unsigned int i2c_mii_phy_addr(int phy_id)
 29{
 30	return phy_id + 0x40;
 31}
 32
 33static int i2c_mii_read_default_c45(struct mii_bus *bus, int phy_id, int devad,
 34				    int reg)
 35{
 36	struct i2c_adapter *i2c = bus->priv;
 37	struct i2c_msg msgs[2];
 38	u8 addr[3], data[2], *p;
 39	int bus_addr, ret;
 40
 41	if (!i2c_mii_valid_phy_id(phy_id))
 42		return 0xffff;
 43
 44	p = addr;
 45	if (devad >= 0) {
 46		*p++ = 0x20 | devad;
 47		*p++ = reg >> 8;
 48	}
 49	*p++ = reg;
 50
 51	bus_addr = i2c_mii_phy_addr(phy_id);
 52	msgs[0].addr = bus_addr;
 53	msgs[0].flags = 0;
 54	msgs[0].len = p - addr;
 55	msgs[0].buf = addr;
 56	msgs[1].addr = bus_addr;
 57	msgs[1].flags = I2C_M_RD;
 58	msgs[1].len = sizeof(data);
 59	msgs[1].buf = data;
 60
 61	ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs));
 62	if (ret != ARRAY_SIZE(msgs))
 63		return 0xffff;
 64
 65	return data[0] << 8 | data[1];
 66}
 67
 68static int i2c_mii_write_default_c45(struct mii_bus *bus, int phy_id,
 69				     int devad, int reg, u16 val)
 70{
 71	struct i2c_adapter *i2c = bus->priv;
 72	struct i2c_msg msg;
 73	int ret;
 74	u8 data[5], *p;
 75
 76	if (!i2c_mii_valid_phy_id(phy_id))
 77		return 0;
 78
 79	p = data;
 80	if (devad >= 0) {
 81		*p++ = devad;
 82		*p++ = reg >> 8;
 83	}
 84	*p++ = reg;
 85	*p++ = val >> 8;
 86	*p++ = val;
 87
 88	msg.addr = i2c_mii_phy_addr(phy_id);
 89	msg.flags = 0;
 90	msg.len = p - data;
 91	msg.buf = data;
 92
 93	ret = i2c_transfer(i2c, &msg, 1);
 94
 95	return ret < 0 ? ret : 0;
 96}
 97
 98static int i2c_mii_read_default_c22(struct mii_bus *bus, int phy_id, int reg)
 99{
100	return i2c_mii_read_default_c45(bus, phy_id, -1, reg);
101}
102
103static int i2c_mii_write_default_c22(struct mii_bus *bus, int phy_id, int reg,
104				     u16 val)
105{
106	return i2c_mii_write_default_c45(bus, phy_id, -1, reg, val);
107}
108
109static int smbus_byte_mii_read_default_c22(struct mii_bus *bus, int phy_id,
110					   int reg)
111{
112	struct i2c_adapter *i2c = bus->priv;
113	union i2c_smbus_data smbus_data;
114	int val = 0, ret;
115
116	if (!i2c_mii_valid_phy_id(phy_id))
117		return 0;
118
119	i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
120
121	ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
122			       I2C_SMBUS_READ, reg,
123			       I2C_SMBUS_BYTE_DATA, &smbus_data);
124	if (ret < 0)
125		goto unlock;
126
127	val = (smbus_data.byte & 0xff) << 8;
128
129	ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
130			       I2C_SMBUS_READ, reg,
131			       I2C_SMBUS_BYTE_DATA, &smbus_data);
132
133unlock:
134	i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
135
136	if (ret < 0)
137		return ret;
138
139	val |= smbus_data.byte & 0xff;
140
141	return val;
142}
143
144static int smbus_byte_mii_write_default_c22(struct mii_bus *bus, int phy_id,
145					    int reg, u16 val)
146{
147	struct i2c_adapter *i2c = bus->priv;
148	union i2c_smbus_data smbus_data;
149	int ret;
150
151	if (!i2c_mii_valid_phy_id(phy_id))
152		return 0;
153
154	smbus_data.byte = (val & 0xff00) >> 8;
155
156	i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
157
158	ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
159			       I2C_SMBUS_WRITE, reg,
160			       I2C_SMBUS_BYTE_DATA, &smbus_data);
161	if (ret < 0)
162		goto unlock;
163
164	smbus_data.byte = val & 0xff;
165
166	ret = __i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0,
167			       I2C_SMBUS_WRITE, reg,
168			       I2C_SMBUS_BYTE_DATA, &smbus_data);
169
170unlock:
171	i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
172
173	return ret < 0 ? ret : 0;
174}
175
176/* RollBall SFPs do not access internal PHY via I2C address 0x56, but
177 * instead via address 0x51, when SFP page is set to 0x03 and password to
178 * 0xffffffff.
179 *
180 * address  size  contents  description
181 * -------  ----  --------  -----------
182 * 0x80     1     CMD       0x01/0x02/0x04 for write/read/done
183 * 0x81     1     DEV       Clause 45 device
184 * 0x82     2     REG       Clause 45 register
185 * 0x84     2     VAL       Register value
186 */
187#define ROLLBALL_PHY_I2C_ADDR		0x51
188
189#define ROLLBALL_PASSWORD		(SFP_VSL + 3)
190
191#define ROLLBALL_CMD_ADDR		0x80
192#define ROLLBALL_DATA_ADDR		0x81
193
194#define ROLLBALL_CMD_WRITE		0x01
195#define ROLLBALL_CMD_READ		0x02
196#define ROLLBALL_CMD_DONE		0x04
197
198#define SFP_PAGE_ROLLBALL_MDIO		3
199
200static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs,
201			      int num)
202{
203	int ret;
204
205	ret = __i2c_transfer(i2c, msgs, num);
206	if (ret < 0)
207		return ret;
208	else if (ret != num)
209		return -EIO;
210	else
211		return 0;
212}
213
214static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr,
215				   u8 *page)
216{
217	struct i2c_msg msgs[2];
218	u8 addr = SFP_PAGE;
219
220	msgs[0].addr = bus_addr;
221	msgs[0].flags = 0;
222	msgs[0].len = 1;
223	msgs[0].buf = &addr;
224
225	msgs[1].addr = bus_addr;
226	msgs[1].flags = I2C_M_RD;
227	msgs[1].len = 1;
228	msgs[1].buf = page;
229
230	return __i2c_transfer_err(i2c, msgs, 2);
231}
232
233static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr,
234				   u8 page)
235{
236	struct i2c_msg msg;
237	u8 buf[2];
238
239	buf[0] = SFP_PAGE;
240	buf[1] = page;
241
242	msg.addr = bus_addr;
243	msg.flags = 0;
244	msg.len = 2;
245	msg.buf = buf;
246
247	return __i2c_transfer_err(i2c, &msg, 1);
248}
249
250/* In order to not interfere with other SFP code (which possibly may manipulate
251 * SFP_PAGE), for every transfer we do this:
252 *   1. lock the bus
253 *   2. save content of SFP_PAGE
254 *   3. set SFP_PAGE to 3
255 *   4. do the transfer
256 *   5. restore original SFP_PAGE
257 *   6. unlock the bus
258 * Note that one might think that steps 2 to 5 could be theoretically done all
259 * in one call to i2c_transfer (by constructing msgs array in such a way), but
260 * unfortunately tests show that this does not work :-( Changed SFP_PAGE does
261 * not take into account until i2c_transfer() is done.
262 */
263static int i2c_transfer_rollball(struct i2c_adapter *i2c,
264				 struct i2c_msg *msgs, int num)
265{
266	int ret, main_err = 0;
267	u8 saved_page;
268
269	i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
270
271	/* save original page */
272	ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page);
273	if (ret)
274		goto unlock;
275
276	/* change to RollBall MDIO page */
277	ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO);
278	if (ret)
279		goto unlock;
280
281	/* do the transfer; we try to restore original page if this fails */
282	ret = __i2c_transfer_err(i2c, msgs, num);
283	if (ret)
284		main_err = ret;
285
286	/* restore original page */
287	ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page);
288
289unlock:
290	i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
291
292	return main_err ? : ret;
293}
294
295static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf,
296				 size_t len)
297{
298	struct i2c_adapter *i2c = bus->priv;
299	struct i2c_msg msgs[2];
300	u8 cmd_addr, tmp, *res;
301	int i, ret;
302
303	cmd_addr = ROLLBALL_CMD_ADDR;
304
305	res = buf ? buf : &tmp;
306	len = buf ? len : 1;
307
308	msgs[0].addr = bus_addr;
309	msgs[0].flags = 0;
310	msgs[0].len = 1;
311	msgs[0].buf = &cmd_addr;
312
313	msgs[1].addr = bus_addr;
314	msgs[1].flags = I2C_M_RD;
315	msgs[1].len = len;
316	msgs[1].buf = res;
317
318	/* By experiment it takes up to 70 ms to access a register for these
319	 * SFPs. Sleep 20ms between iterations and try 10 times.
320	 */
321	i = 10;
322	do {
323		msleep(20);
324
325		ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
326		if (ret)
327			return ret;
328
329		if (*res == ROLLBALL_CMD_DONE)
330			return 0;
331	} while (i-- > 0);
332
333	dev_dbg(&bus->dev, "poll timed out\n");
334
335	return -ETIMEDOUT;
336}
337
338static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd,
339				u8 *data, size_t len)
340{
341	struct i2c_adapter *i2c = bus->priv;
342	struct i2c_msg msgs[2];
343	u8 cmdbuf[2];
344
345	cmdbuf[0] = ROLLBALL_CMD_ADDR;
346	cmdbuf[1] = cmd;
347
348	msgs[0].addr = bus_addr;
349	msgs[0].flags = 0;
350	msgs[0].len = len;
351	msgs[0].buf = data;
352
353	msgs[1].addr = bus_addr;
354	msgs[1].flags = 0;
355	msgs[1].len = sizeof(cmdbuf);
356	msgs[1].buf = cmdbuf;
357
358	return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
359}
360
361static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int devad,
362				 int reg)
363{
364	u8 buf[4], res[6];
365	int bus_addr, ret;
366	u16 val;
367
368	bus_addr = i2c_mii_phy_addr(phy_id);
369	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
370		return 0xffff;
371
372	buf[0] = ROLLBALL_DATA_ADDR;
373	buf[1] = devad;
374	buf[2] = (reg >> 8) & 0xff;
375	buf[3] = reg & 0xff;
376
377	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf,
378				   sizeof(buf));
379	if (ret < 0)
380		return ret;
381
382	ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res));
383	if (ret == -ETIMEDOUT)
384		return 0xffff;
385	else if (ret < 0)
386		return ret;
387
388	val = res[4] << 8 | res[5];
389
390	return val;
391}
392
393static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad,
394				  int reg, u16 val)
395{
396	int bus_addr, ret;
397	u8 buf[6];
398
399	bus_addr = i2c_mii_phy_addr(phy_id);
400	if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
401		return 0;
402
403	buf[0] = ROLLBALL_DATA_ADDR;
404	buf[1] = devad;
405	buf[2] = (reg >> 8) & 0xff;
406	buf[3] = reg & 0xff;
407	buf[4] = val >> 8;
408	buf[5] = val & 0xff;
409
410	ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf,
411				   sizeof(buf));
412	if (ret < 0)
413		return ret;
414
415	ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0);
416	if (ret < 0)
417		return ret;
418
419	return 0;
420}
421
422static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
423{
424	struct i2c_msg msg;
425	u8 pw[5];
426	int ret;
427
428	pw[0] = ROLLBALL_PASSWORD;
429	pw[1] = 0xff;
430	pw[2] = 0xff;
431	pw[3] = 0xff;
432	pw[4] = 0xff;
433
434	msg.addr = ROLLBALL_PHY_I2C_ADDR;
435	msg.flags = 0;
436	msg.len = sizeof(pw);
437	msg.buf = pw;
438
439	ret = i2c_transfer(i2c, &msg, 1);
440	if (ret < 0)
441		return ret;
442	else if (ret != 1)
443		return -EIO;
444	else
445		return 0;
446}
447
448static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c,
449					 enum mdio_i2c_proto protocol)
450{
451	if (i2c_check_functionality(i2c, I2C_FUNC_I2C))
452		return true;
453
454	if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
455	    protocol == MDIO_I2C_MARVELL_C22)
456		return true;
457
458	return false;
459}
460
461struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
462			       enum mdio_i2c_proto protocol)
463{
464	struct mii_bus *mii;
465	int ret;
466
467	if (!mdio_i2c_check_functionality(i2c, protocol))
468		return ERR_PTR(-EINVAL);
469
470	mii = mdiobus_alloc();
471	if (!mii)
472		return ERR_PTR(-ENOMEM);
473
474	snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent));
475	mii->parent = parent;
476	mii->priv = i2c;
477
478	/* Only use SMBus if we have no other choice */
479	if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA) &&
480	    !i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
481		mii->read = smbus_byte_mii_read_default_c22;
482		mii->write = smbus_byte_mii_write_default_c22;
483		return mii;
484	}
485
486	switch (protocol) {
487	case MDIO_I2C_ROLLBALL:
488		ret = i2c_mii_init_rollball(i2c);
489		if (ret < 0) {
490			dev_err(parent,
491				"Cannot initialize RollBall MDIO I2C protocol: %d\n",
492				ret);
493			mdiobus_free(mii);
494			return ERR_PTR(ret);
495		}
496
497		mii->read_c45 = i2c_mii_read_rollball;
498		mii->write_c45 = i2c_mii_write_rollball;
499		break;
500	default:
501		mii->read = i2c_mii_read_default_c22;
502		mii->write = i2c_mii_write_default_c22;
503		mii->read_c45 = i2c_mii_read_default_c45;
504		mii->write_c45 = i2c_mii_write_default_c45;
505		break;
506	}
507
508	return mii;
509}
510EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
511
512MODULE_AUTHOR("Russell King");
513MODULE_DESCRIPTION("MDIO I2C bridge library");
514MODULE_LICENSE("GPL v2");
~/ Read-only file preview.