OSDN Git Service

net: dsa: mt7530: MT7530 optional GPIO support
authorDENG Qingfang <dqfext@gmail.com>
Mon, 25 Jan 2021 04:43:22 +0000 (12:43 +0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 26 Jan 2021 02:29:04 +0000 (18:29 -0800)
MT7530's LED controller can drive up to 15 LED/GPIOs.

Add support for GPIO control and allow users to use its GPIOs by
setting gpio-controller property in device tree.

Signed-off-by: DENG Qingfang <dqfext@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h

index d219619..eb13ba7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
 #include <net/dsa.h>
 
 #include "mt7530.h"
@@ -1622,6 +1623,109 @@ mtk_get_tag_protocol(struct dsa_switch *ds, int port,
        }
 }
 
+static inline u32
+mt7530_gpio_to_bit(unsigned int offset)
+{
+       /* Map GPIO offset to register bit
+        * [ 2: 0]  port 0 LED 0..2 as GPIO 0..2
+        * [ 6: 4]  port 1 LED 0..2 as GPIO 3..5
+        * [10: 8]  port 2 LED 0..2 as GPIO 6..8
+        * [14:12]  port 3 LED 0..2 as GPIO 9..11
+        * [18:16]  port 4 LED 0..2 as GPIO 12..14
+        */
+       return BIT(offset + offset / 3);
+}
+
+static int
+mt7530_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mt7530_priv *priv = gpiochip_get_data(gc);
+       u32 bit = mt7530_gpio_to_bit(offset);
+
+       return !!(mt7530_read(priv, MT7530_LED_GPIO_DATA) & bit);
+}
+
+static void
+mt7530_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+       struct mt7530_priv *priv = gpiochip_get_data(gc);
+       u32 bit = mt7530_gpio_to_bit(offset);
+
+       if (value)
+               mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
+       else
+               mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
+}
+
+static int
+mt7530_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mt7530_priv *priv = gpiochip_get_data(gc);
+       u32 bit = mt7530_gpio_to_bit(offset);
+
+       return (mt7530_read(priv, MT7530_LED_GPIO_DIR) & bit) ?
+               GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int
+mt7530_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mt7530_priv *priv = gpiochip_get_data(gc);
+       u32 bit = mt7530_gpio_to_bit(offset);
+
+       mt7530_clear(priv, MT7530_LED_GPIO_OE, bit);
+       mt7530_clear(priv, MT7530_LED_GPIO_DIR, bit);
+
+       return 0;
+}
+
+static int
+mt7530_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
+{
+       struct mt7530_priv *priv = gpiochip_get_data(gc);
+       u32 bit = mt7530_gpio_to_bit(offset);
+
+       mt7530_set(priv, MT7530_LED_GPIO_DIR, bit);
+
+       if (value)
+               mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
+       else
+               mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
+
+       mt7530_set(priv, MT7530_LED_GPIO_OE, bit);
+
+       return 0;
+}
+
+static int
+mt7530_setup_gpio(struct mt7530_priv *priv)
+{
+       struct device *dev = priv->dev;
+       struct gpio_chip *gc;
+
+       gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+       if (!gc)
+               return -ENOMEM;
+
+       mt7530_write(priv, MT7530_LED_GPIO_OE, 0);
+       mt7530_write(priv, MT7530_LED_GPIO_DIR, 0);
+       mt7530_write(priv, MT7530_LED_IO_MODE, 0);
+
+       gc->label = "mt7530";
+       gc->parent = dev;
+       gc->owner = THIS_MODULE;
+       gc->get_direction = mt7530_gpio_get_direction;
+       gc->direction_input = mt7530_gpio_direction_input;
+       gc->direction_output = mt7530_gpio_direction_output;
+       gc->get = mt7530_gpio_get;
+       gc->set = mt7530_gpio_set;
+       gc->base = -1;
+       gc->ngpio = 15;
+       gc->can_sleep = true;
+
+       return devm_gpiochip_add_data(dev, gc, priv);
+}
+
 static int
 mt7530_setup(struct dsa_switch *ds)
 {
@@ -1763,6 +1867,12 @@ mt7530_setup(struct dsa_switch *ds)
                }
        }
 
+       if (of_property_read_bool(priv->dev->of_node, "gpio-controller")) {
+               ret = mt7530_setup_gpio(priv);
+               if (ret)
+                       return ret;
+       }
+
        mt7530_setup_port5(ds, interface);
 
        /* Flush the FDB table */
index 32d8969..64a9bb3 100644 (file)
@@ -554,6 +554,26 @@ enum mt7531_clk_skew {
 #define  MT7531_GPIO12_RG_RXD3_MASK    GENMASK(19, 16)
 #define  MT7531_EXT_P_MDIO_12          (2 << 16)
 
+/* Registers for LED GPIO control (MT7530 only)
+ * All registers follow this pattern:
+ * [ 2: 0]  port 0
+ * [ 6: 4]  port 1
+ * [10: 8]  port 2
+ * [14:12]  port 3
+ * [18:16]  port 4
+ */
+
+/* LED enable, 0: Disable, 1: Enable (Default) */
+#define MT7530_LED_EN                  0x7d00
+/* LED mode, 0: GPIO mode, 1: PHY mode (Default) */
+#define MT7530_LED_IO_MODE             0x7d04
+/* GPIO direction, 0: Input, 1: Output */
+#define MT7530_LED_GPIO_DIR            0x7d10
+/* GPIO output enable, 0: Disable, 1: Enable */
+#define MT7530_LED_GPIO_OE             0x7d14
+/* GPIO value, 0: Low, 1: High */
+#define MT7530_LED_GPIO_DATA           0x7d18
+
 #define MT7530_CREV                    0x7ffc
 #define  CHIP_NAME_SHIFT               16
 #define  MT7530_ID                     0x7530