// SPDX-License-Identifier: GPL-2.0+ /* Realtek Simple Management Interface (SMI) driver * It can be discussed how "simple" this interface is. * * The SMI protocol piggy-backs the MDIO MDC and MDIO signals levels * but the protocol is not MDIO at all. Instead it is a Realtek * pecularity that need to bit-bang the lines in a special way to * communicate with the switch. * * ASICs we intend to support with this driver: * * RTL8366 - The original version, apparently * RTL8369 - Similar enough to have the same datsheet as RTL8366 * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite * different register layout from the other two * RTL8366S - Is this "RTL8366 super"? * RTL8367 - Has an OpenWRT driver as well * RTL8368S - Seems to be an alternative name for RTL8366RB * RTL8370 - Also uses SMI * * Copyright (C) 2017 Linus Walleij <[email protected]> * Copyright (C) 2010 Antti Seppälä <[email protected]> * Copyright (C) 2010 Roman Yeryomin <[email protected]> * Copyright (C) 2011 Colin Leitner <[email protected]> * Copyright (C) 2009-2010 Gabor Juhos <[email protected]> */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/spinlock.h> #include <linux/skbuff.h> #include <linux/of.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/bitops.h> #include <linux/if_bridge.h> #include "realtek.h" #include "realtek-smi.h" #include "rtl83xx.h" #define REALTEK_SMI_ACK_RETRY_COUNT … static inline void realtek_smi_clk_delay(struct realtek_priv *priv) { … } static void realtek_smi_start(struct realtek_priv *priv) { … } static void realtek_smi_stop(struct realtek_priv *priv) { … } static void realtek_smi_write_bits(struct realtek_priv *priv, u32 data, u32 len) { … } static void realtek_smi_read_bits(struct realtek_priv *priv, u32 len, u32 *data) { … } static int realtek_smi_wait_for_ack(struct realtek_priv *priv) { … } static int realtek_smi_write_byte(struct realtek_priv *priv, u8 data) { … } static int realtek_smi_write_byte_noack(struct realtek_priv *priv, u8 data) { … } static int realtek_smi_read_byte0(struct realtek_priv *priv, u8 *data) { … } static int realtek_smi_read_byte1(struct realtek_priv *priv, u8 *data) { … } static int realtek_smi_read_reg(struct realtek_priv *priv, u32 addr, u32 *data) { … } static int realtek_smi_write_reg(struct realtek_priv *priv, u32 addr, u32 data, bool ack) { … } /* There is one single case when we need to use this accessor and that * is when issueing soft reset. Since the device reset as soon as we write * that bit, no ACK will come back for natural reasons. */ static int realtek_smi_write_reg_noack(void *ctx, u32 reg, u32 val) { … } /* Regmap accessors */ static int realtek_smi_write(void *ctx, u32 reg, u32 val) { … } static int realtek_smi_read(void *ctx, u32 reg, u32 *val) { … } static const struct realtek_interface_info realtek_smi_info = …; /** * realtek_smi_probe() - Probe a platform device for an SMI-connected switch * @pdev: platform_device to probe on. * * This function should be used as the .probe in a platform_driver. After * calling the common probe function for both interfaces, it initializes the * values specific for SMI-connected devices. Finally, it calls a common * function to register the DSA switch. * * Context: Can sleep. Takes and releases priv->map_lock. * Return: Returns 0 on success, a negative error on failure. */ int realtek_smi_probe(struct platform_device *pdev) { … } EXPORT_SYMBOL_NS_GPL(…); /** * realtek_smi_remove() - Remove the driver of a SMI-connected switch * @pdev: platform_device to be removed. * * This function should be used as the .remove_new in a platform_driver. First * it unregisters the DSA switch and then it calls the common remove function. * * Context: Can sleep. * Return: Nothing. */ void realtek_smi_remove(struct platform_device *pdev) { … } EXPORT_SYMBOL_NS_GPL(…); /** * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch * @pdev: platform_device shutting down. * * This function should be used as the .shutdown in a platform_driver. It calls * the common shutdown function. * * Context: Can sleep. * Return: Nothing. */ void realtek_smi_shutdown(struct platform_device *pdev) { … } EXPORT_SYMBOL_NS_GPL(…);