Lines Matching +full:smi +full:- +full:mdio

1 // SPDX-License-Identifier: GPL-2.0+
2 /* Realtek Simple Management Interface (SMI) driver
5 * The SMI protocol piggy-backs the MDIO MDC and MDIO signals levels
6 * but the protocol is not MDIO at all. Instead it is a Realtek
7 * pecularity that need to bit-bang the lines in a special way to
12 * RTL8366 - The original version, apparently
13 * RTL8369 - Similar enough to have the same datsheet as RTL8366
14 * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite
16 * RTL8366S - Is this "RTL8366 super"?
17 * RTL8367 - Has an OpenWRT driver as well
18 * RTL8368S - Seems to be an alternative name for RTL8366RB
19 * RTL8370 - Also uses SMI
25 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
48 ndelay(priv->clk_delay); in realtek_smi_clk_delay()
56 gpiod_direction_output(priv->mdc, 0); in realtek_smi_start()
57 gpiod_direction_output(priv->mdio, 1); in realtek_smi_start()
60 /* CLK 1: 0 -> 1, 1 -> 0 */ in realtek_smi_start()
61 gpiod_set_value(priv->mdc, 1); in realtek_smi_start()
63 gpiod_set_value(priv->mdc, 0); in realtek_smi_start()
67 gpiod_set_value(priv->mdc, 1); in realtek_smi_start()
69 gpiod_set_value(priv->mdio, 0); in realtek_smi_start()
71 gpiod_set_value(priv->mdc, 0); in realtek_smi_start()
73 gpiod_set_value(priv->mdio, 1); in realtek_smi_start()
79 gpiod_set_value(priv->mdio, 0); in realtek_smi_stop()
80 gpiod_set_value(priv->mdc, 1); in realtek_smi_stop()
82 gpiod_set_value(priv->mdio, 1); in realtek_smi_stop()
84 gpiod_set_value(priv->mdc, 1); in realtek_smi_stop()
86 gpiod_set_value(priv->mdc, 0); in realtek_smi_stop()
88 gpiod_set_value(priv->mdc, 1); in realtek_smi_stop()
92 gpiod_set_value(priv->mdc, 0); in realtek_smi_stop()
94 gpiod_set_value(priv->mdc, 1); in realtek_smi_stop()
97 gpiod_direction_input(priv->mdio); in realtek_smi_stop()
98 gpiod_direction_input(priv->mdc); in realtek_smi_stop()
103 for (; len > 0; len--) { in realtek_smi_write_bits()
107 gpiod_set_value(priv->mdio, !!(data & (1 << (len - 1)))); in realtek_smi_write_bits()
111 gpiod_set_value(priv->mdc, 1); in realtek_smi_write_bits()
113 gpiod_set_value(priv->mdc, 0); in realtek_smi_write_bits()
119 gpiod_direction_input(priv->mdio); in realtek_smi_read_bits()
121 for (*data = 0; len > 0; len--) { in realtek_smi_read_bits()
127 gpiod_set_value(priv->mdc, 1); in realtek_smi_read_bits()
129 u = !!gpiod_get_value(priv->mdio); in realtek_smi_read_bits()
130 gpiod_set_value(priv->mdc, 0); in realtek_smi_read_bits()
132 *data |= (u << (len - 1)); in realtek_smi_read_bits()
135 gpiod_direction_output(priv->mdio, 0); in realtek_smi_read_bits()
151 dev_err(priv->dev, "ACK timeout\n"); in realtek_smi_wait_for_ack()
152 return -ETIMEDOUT; in realtek_smi_wait_for_ack()
206 spin_lock_irqsave(&priv->lock, flags); in realtek_smi_read_reg()
211 ret = realtek_smi_write_byte(priv, priv->cmd_read); in realtek_smi_read_reg()
236 spin_unlock_irqrestore(&priv->lock, flags); in realtek_smi_read_reg()
247 spin_lock_irqsave(&priv->lock, flags); in realtek_smi_write_reg()
252 ret = realtek_smi_write_byte(priv, priv->cmd_write); in realtek_smi_write_reg()
283 spin_unlock_irqrestore(&priv->lock, flags); in realtek_smi_write_reg()
317 mutex_lock(&priv->map_lock); in realtek_smi_lock()
324 mutex_unlock(&priv->map_lock); in realtek_smi_unlock()
356 struct realtek_priv *priv = bus->priv; in realtek_smi_mdio_read()
358 return priv->ops->phy_read(priv, addr, regnum); in realtek_smi_mdio_read()
364 struct realtek_priv *priv = bus->priv; in realtek_smi_mdio_write()
366 return priv->ops->phy_write(priv, addr, regnum, val); in realtek_smi_mdio_write()
371 struct realtek_priv *priv = ds->priv; in realtek_smi_setup_mdio()
375 mdio_np = of_get_compatible_child(priv->dev->of_node, "realtek,smi-mdio"); in realtek_smi_setup_mdio()
377 dev_err(priv->dev, "no MDIO bus node\n"); in realtek_smi_setup_mdio()
378 return -ENODEV; in realtek_smi_setup_mdio()
381 priv->slave_mii_bus = devm_mdiobus_alloc(priv->dev); in realtek_smi_setup_mdio()
382 if (!priv->slave_mii_bus) { in realtek_smi_setup_mdio()
383 ret = -ENOMEM; in realtek_smi_setup_mdio()
386 priv->slave_mii_bus->priv = priv; in realtek_smi_setup_mdio()
387 priv->slave_mii_bus->name = "SMI slave MII"; in realtek_smi_setup_mdio()
388 priv->slave_mii_bus->read = realtek_smi_mdio_read; in realtek_smi_setup_mdio()
389 priv->slave_mii_bus->write = realtek_smi_mdio_write; in realtek_smi_setup_mdio()
390 snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "SMI-%d", in realtek_smi_setup_mdio()
391 ds->index); in realtek_smi_setup_mdio()
392 priv->slave_mii_bus->dev.of_node = mdio_np; in realtek_smi_setup_mdio()
393 priv->slave_mii_bus->parent = priv->dev; in realtek_smi_setup_mdio()
394 ds->slave_mii_bus = priv->slave_mii_bus; in realtek_smi_setup_mdio()
396 ret = devm_of_mdiobus_register(priv->dev, priv->slave_mii_bus, mdio_np); in realtek_smi_setup_mdio()
398 dev_err(priv->dev, "unable to register MDIO bus %s\n", in realtek_smi_setup_mdio()
399 priv->slave_mii_bus->id); in realtek_smi_setup_mdio()
414 struct device *dev = &pdev->dev; in realtek_smi_probe()
421 np = dev->of_node; in realtek_smi_probe()
423 priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); in realtek_smi_probe()
425 return -ENOMEM; in realtek_smi_probe()
426 priv->chip_data = (void *)priv + sizeof(*priv); in realtek_smi_probe()
428 mutex_init(&priv->map_lock); in realtek_smi_probe()
432 priv->map = devm_regmap_init(dev, NULL, priv, &rc); in realtek_smi_probe()
433 if (IS_ERR(priv->map)) { in realtek_smi_probe()
434 ret = PTR_ERR(priv->map); in realtek_smi_probe()
440 priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); in realtek_smi_probe()
441 if (IS_ERR(priv->map_nolock)) { in realtek_smi_probe()
442 ret = PTR_ERR(priv->map_nolock); in realtek_smi_probe()
448 priv->dev = dev; in realtek_smi_probe()
449 priv->clk_delay = var->clk_delay; in realtek_smi_probe()
450 priv->cmd_read = var->cmd_read; in realtek_smi_probe()
451 priv->cmd_write = var->cmd_write; in realtek_smi_probe()
452 priv->ops = var->ops; in realtek_smi_probe()
454 priv->setup_interface = realtek_smi_setup_mdio; in realtek_smi_probe()
455 priv->write_reg_noack = realtek_smi_write_reg_noack; in realtek_smi_probe()
458 spin_lock_init(&priv->lock); in realtek_smi_probe()
462 priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); in realtek_smi_probe()
463 if (IS_ERR(priv->reset)) { in realtek_smi_probe()
465 return PTR_ERR(priv->reset); in realtek_smi_probe()
467 if (priv->reset) { in realtek_smi_probe()
468 gpiod_set_value(priv->reset, 1); in realtek_smi_probe()
471 gpiod_set_value(priv->reset, 0); in realtek_smi_probe()
476 /* Fetch MDIO pins */ in realtek_smi_probe()
477 priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); in realtek_smi_probe()
478 if (IS_ERR(priv->mdc)) in realtek_smi_probe()
479 return PTR_ERR(priv->mdc); in realtek_smi_probe()
480 priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); in realtek_smi_probe()
481 if (IS_ERR(priv->mdio)) in realtek_smi_probe()
482 return PTR_ERR(priv->mdio); in realtek_smi_probe()
484 priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); in realtek_smi_probe()
486 ret = priv->ops->detect(priv); in realtek_smi_probe()
492 priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); in realtek_smi_probe()
493 if (!priv->ds) in realtek_smi_probe()
494 return -ENOMEM; in realtek_smi_probe()
496 priv->ds->dev = dev; in realtek_smi_probe()
497 priv->ds->num_ports = priv->num_ports; in realtek_smi_probe()
498 priv->ds->priv = priv; in realtek_smi_probe()
500 priv->ds->ops = var->ds_ops_smi; in realtek_smi_probe()
501 ret = dsa_register_switch(priv->ds); in realtek_smi_probe()
516 dsa_unregister_switch(priv->ds); in realtek_smi_remove()
517 if (priv->slave_mii_bus) in realtek_smi_remove()
518 of_node_put(priv->slave_mii_bus->dev.of_node); in realtek_smi_remove()
521 if (priv->reset) in realtek_smi_remove()
522 gpiod_set_value(priv->reset, 1); in realtek_smi_remove()
534 dsa_switch_shutdown(priv->ds); in realtek_smi_shutdown()
558 .name = "realtek-smi",
568 MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via SMI interface");